美文网首页Android进阶之路
Android关键字persistent原理分析

Android关键字persistent原理分析

作者: 罗公子Coding | 来源:发表于2017-12-13 11:33 被阅读798次

    在Android程序开发时我们会接触到一些系统为了某些功能而定义的关键属性,例如在AndroidManifest.xml文件中

    经常看到的persistent、process等,下面是自己对persistent关键字的分析,直奔主题。

    一、persistent属性作用

    1、定义

    该属性的定义在frameworks/base/core/res/res/values/attrs_manifest.xml中,其定义如下:

    
        <!-- Flag to control special persistent mode of an application.  This should
    
             not normally be used by applications; it requires that the system keep
    
             your application running at all times. -->
    
        <attr name="persistent" format="boolean" />
    
    
    
    

    通过官方注释我知道该属性用于是否让你的应用一直处于运行状态(通常说的常驻内存)。设置
    该属性为true的app具有如下特点:

    • 在系统启动的时候会被系统启动起来

    • 在该app被强制杀掉后系统会重新启动该app,这种情况只针对系统内置app,第三方安装的app不会被重启

    2、使用

    persistent属性是用于application标签上的,用法为:

    AndroidManifest.xml

    
    <application
    
        android:persistent="true|false"
    
    >
    
    
    
    </application>
    
    
    
    

    persistent的值默认为false

    二、原理分析

    通过第一点对persistent的功能说明后我们通过源码来分析一下它的工作原理

    1、persistent属性的解析

    该属性的解析主要在app被安装或者系统启动的时候发生

    解析代码:

    frameworks/base/core/java/com/android/content/pm/PackageParser.java

    
    private boolean parseBaseApplication(Package owner, Resources res,
    
                XmlResourceParser parser, int flags, String[] outError)
    
            throws XmlPullParserException, IOException {
    
    final ApplicationInfo ai = owner.applicationInfo;
    
        //.......................
    
        
    
        if ((flags&PARSE_IS_SYSTEM) != 0) {
    
                if (sa.getBoolean(
    
                        com.android.internal.R.styleable.AndroidManifestApplication_persistent,
    
                        false)) {
    
                    ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
    
                }
    
            }
    
    
    
    
    
    //.............
    
    
    
    
    
    
    
    
    }
    
    

    在解析完包信息之后系统会将解析好的所有包信息存放到PKMS中的mPackages的map中,而ApplicationInfo的flag中有一个bit位用于保存该app是否是persistent的。这里只是把保存persistent的flag设置为FLAG_PERSISTENT。在AndroidManifest设置了persistent为true的app是否能够在被异常杀死后能够得到重启的权力需要取决于该app对应的ProcessRecord的persistent属性,该属性只有在你的app既在AndroidManifest中配置了persistent=“true”,又是系统内置app时才会被设置为true。

    2、系统启动时启动persistent为true的app

    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    在系统启动时ActivityManagerService的systemReady()方法会将所有在AndroidManifest设置了persistent为true的app拉起来

    
     public void systemReady(final Runnable goingCallback) {
    
    ......
    
    synchronized (this) {
    
                // Only start up encryption-aware persistent apps; once user is
    
                // unlocked we'll come back around and start unaware apps
    
                startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
    
    
    
                // Start up initial activity.
    
                mBooting = true;
    
                // Enable home activity for system user, so that the system can always boot
    
                if (UserManager.isSplitSystemUser()) {
    
                    ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
    
                    try {
    
                        AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
    
                                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
    
                                UserHandle.USER_SYSTEM);
    
                    } catch (RemoteException e) {
    
                        throw e.rethrowAsRuntimeException();
    
                    }
    
                }
    
    ......
    
    }
    
    

    systemReady中调用了startPersistentApps() 方法

    
    
    
    private void startPersistentApps(int matchFlags) {
    
            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
    
    
    
            synchronized (this) {
    
                try {
    
                    final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
    
                            .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
    
                    for (ApplicationInfo app : apps) {
    
                        if (!"android".equals(app.packageName)) {
    
                            addAppLocked(app, false, null /* ABI override */);
    
                        }
    
                    }
    
                } catch (RemoteException ex) {
    
                }
    
            }
    
        }
    
    

    在startPersistentApps方法中首先是调用PackageManageServices的getPersistentApplications方法获取到所有在AndroidManifest设置了persistent为true的app,然后调用addAppLocked方法去启动他们。这样在AndroidManifest设置了persistent为true的app就随着系统的启动而启动了。
    下面看一下getPersistentApplications方法,该方法调用了PKMS中的getPersistentApplicationsInternal方法。

    
    
    private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
    
            final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
    
    
    
            // reader
    
            synchronized (mPackages) {
    
                final Iterator<PackageParser.Package> i = mPackages.values().iterator();
    
                final int userId = UserHandle.getCallingUserId();
    
                while (i.hasNext()) {
    
                    final PackageParser.Package p = i.next();
    
                    if (p.applicationInfo == null) continue;
    
    
    
                    final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
    
                            && !p.applicationInfo.isDirectBootAware();
    
                    final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
    
                            && p.applicationInfo.isDirectBootAware();
    
    
    
                    if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
    
                            && (!mSafeMode || isSystemApp(p))
    
                            && (matchesUnaware || matchesAware)) {
    
                        PackageSetting ps = mSettings.mPackages.get(p.packageName);
    
                        if (ps != null) {
    
                            ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
    
                                    ps.readUserState(userId), userId);
    
                            if (ai != null) {
    
                                finalList.add(ai);
    
                            }
    
                        }
    
                    }
    
                }
    
            }
    
    
    
            return finalList;
    
        }
    
    
    
    

    该方法会遍历mPackages中的所有app,并找到其中在AndroidManifest设置了persistent为true的应用。从代码中可以看到,persistent为true并且是系统app的话一定会被选中,但是如果是第三方安装的应用的话只能在非“安全模式”下才会被选中。

    之后调用addAppLocked方法启动app:

    
    
    
    
    
    
        final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
    
                String abiOverride) {
    
            ProcessRecord app;
    
            //传递进来的isolated=false,所有一定会调用getProcessRecordLocked方法,但是由于是第一次启动,所有返回的app = null
    
            if (!isolated) {
    
                app = getProcessRecordLocked(info.processName, info.uid, true);
    
            } else {
    
                app = null;
    
            }
    
    
    
            if (app == null) {
    
                 //为新的app创建新的ProcessRecord对象
    
                app = newProcessRecordLocked(info, null, isolated, 0);
    
                updateLruProcessLocked(app, false, null);
    
                updateOomAdjLocked();
    
            }
    
    
    
            // This package really, really can not be stopped.
    
            try {
    
                //由于是开机第一次启动,所以新的app的启动状态是将要被启动状态,所以
    
                //该app的停止状态stoped被设置为false
    
                AppGlobals.getPackageManager().setPackageStoppedState(
    
                        info.packageName, false, UserHandle.getUserId(app.uid));
    
            } catch (RemoteException e) {
    
            } catch (IllegalArgumentException e) {
    
                Slog.w(TAG, "Failed trying to unstop package "
    
                        + info.packageName + ": " + e);
    
            }
    
          
    
            //在这里对persistent的app进行过滤,只有既是系统app,persistent为true的app才会在
    
           //异常死亡之后被重启
    
            if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
    
                app.persistent = true;
    
                app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
    
            }
    
            //如果该app已经启动了,则不用处理,否则调用startProcessLocked方法启动app。
    
            //由于启动app是异步进行的,会将正在启动而还没有启动完成的app添加到
    
            //mPersistentStartingProcesses列表中。当启动完成后 再移除
    
            if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
    
                mPersistentStartingProcesses.add(app);
    
                //启动该app
    
                startProcessLocked(app, "added application", app.processName, abiOverride,
    
                        null /* entryPoint */, null /* entryPointArgs */);
    
            }
    
    
    
            return app;
    
        }
    
    }
    
    

    接下来调用startProcessLocked方法启动app进程,在app启动完成后会在ActivityThread中调用AMS的attachApplication,将该app从mPersistentStartingProcesses中移除,并注册一个死亡讣告监听器AppDeathRecipient,用于在app异常被杀后的处理工作。

    
    private final boolean attachApplicationLocked(IApplicationThread thread,
    
                int pid) {
    
    
    
    ......
    
    try {
    
                //注册死亡讣告监听器AppDeathRecipient
    
                AppDeathRecipient adr = new AppDeathRecipient(
    
                        app, pid, thread);
    
                thread.asBinder().linkToDeath(adr, 0);
    
                app.deathRecipient = adr;
    
            } catch (RemoteException e) {
    
                app.resetPackageList(mProcessStats);
    
                startProcessLocked(app, "link fail", processName);
    
                return false;
    
            }
    
    ......
    
    }
    
    

    3、app被异常结束后系统重新启动persistent为true的app

    进程启动时为app注册了一个死亡讣告,当该app被杀掉之后会调用AppDeathRecipient的binderDied方法,该方法会调用appDiedLocked方法进行善后处理,系统在进程死掉之后会对死掉的进程进行清理和资源回收,但是在这个过程中如果你的app是persistent的话会被重启:

    binderDied

      |
    
      |——appDiedLocked
    
                     |
    
                     |——handleAppDiedLocked
    
                                          |
    
                                          |——cleanUpApplicationRecordLocked
    

    在cleanUpApplicationRecordLocked中对persistent为true的app进行重启

    
    
    private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
    
                boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
    
    ...............
       //非persistent的app被杀死后就被清理掉
    
    
        if (!app.persistent || app.isolated) {
    
                if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
    
                        "Removing non-persistent process during cleanup: " + app);
    
                if (!replacingPid) {
    
                    removeProcessNameLocked(app.processName, app.uid, app);
    
                }
    
                if (mHeavyWeightProcess == app) {
    
                    mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
    
                            mHeavyWeightProcess.userId, 0));
    
                    mHeavyWeightProcess = null;
    
                }
    
            } else if (!app.removed) {
    
                // This app is persistent, so we need to keep its record around.
    
                // If it is not already on the pending app list, add it there
    
                // and start a new process for it.
    
              
    
            //该app是persistent的,需要对其进行重启,并把它添加到正在启动的列表中,并
    
                //设置restart=true
    
                if (mPersistentStartingProcesses.indexOf(app) < 0) {
    
                    mPersistentStartingProcesses.add(app);
    
                    restart = true;
    
                }
    
            }
    
    ....
    
    //经过上面的过滤,会调用这个分支条件重启persistent为true的app
    
     if (restart && !app.isolated) {
    
                // We have components that still need to be running in the
    
                // process, so re-launch it.
    
                if (index < 0) {
    
                    ProcessList.remove(app.pid);
    
                }
    
                addProcessNameLocked(app);
    
                startProcessLocked(app, "restart", app.processName);
    
                return true;
    
            } else if (app.pid > 0 && app.pid != MY_PID) {
    
                // Goodbye!
    
                boolean removed;
    
                synchronized (mPidsSelfLocked) {
    
                    mPidsSelfLocked.remove(app.pid);
    
                    mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
    
                }
    
                mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
    
                if (app.isolated) {
    
                    mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
    
                }
    
                app.setPid(0);
    
            }
    
            return false;
    
    
    
    }
    
    
    
    
    
    

    相关文章

      网友评论

        本文标题:Android关键字persistent原理分析

        本文链接:https://www.haomeiwen.com/subject/exsaixtx.html