Android persistent属性原理分析

以下代码基于Android9.0

persistent属性的定义

开发系统应用时,有时我们需要应用常驻,被杀死后能够自动重启,此时就需要使用到persistent属性,
下面是关于该属性在framework层的定义,属性的定义位于
persistent属性定义在platform/frameworks/base/core/res/res/values/attrs_manifest.xml文件内:

    <!-- 控制应用程序是否处于特殊持久模式的标志,通常情况下不应该被使用,该标志位能够保证应用程序一直运行 -->
    <attr name="persistent" format="boolean" />

persistent属性的使用

开发系统应用时,有时我们需要应用常驻,被杀死后能够自动重启,此时我们就要在应用的AndroidManifest.xml中设置

android:persistent="true"

设置后应用就具备了以下两个特性:

  1. 系统启动时该应用也会启动
  2. 应用被杀死后,系统会重启该应用

persistent属性的原理

persistent属性的解析

当我们应用安装或启动的过程中,会对AndroidManifest.xml进行解析,解析相关的代码位于
platform/frameworks/base/core/java/android/content/pm/PackageParser.java

public class PackageParser {
    ....
    private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
            throws XmlPullParserException, IOException {
                final ApplicationInfo ai = owner.applicationInfo;
                final String pkgName = owner.applicationInfo.packageName;
        
                // 获取 AndroidManifest 的属性
                TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifestApplication);
                ....
                // 获取所设置的 persistent 值,默认为 false
                if (sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
                    false)) {
                // 检查应用是否支持这个权限
                final String requiredFeature = sa.getNonResourceString(com.android.internal.R.styleable
                    .AndroidManifestApplication_persistentWhenFeatureAvailable);
                    if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) {
                        // 将 persistent 的 flag 设置到应用信息中
                        ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
                    }
                }
                ....
    }
    ....
    
}

解析后就会将应用的各种信息保存在PKMS中的一个存储所有应用信息的一个Map中,其中设置了persistent的应用就包含了ApplicationInfo.FLAG_PERSISTENT标志位,之后在系统的启动过程中就会根据这个标志位控制应用的启动。

persistent应用的启动

persistent应用的启动发生在AMSsystemReady方法内,这一部分通过PKMS获取到所有persistent为true的应用列表,之后对列表进行遍历,通过addAppLocked方法将应用一个个启动起来。
对应代码的位于
/platform/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ....
    // 该静态常量用于判断应用是否persistent应用
    private static final int PERSISTENT_MASK =
            ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
            
    // 当系统服务启动时,AMS执行systemReady方法
    public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
            ....
            synchronized (this) {
                // 1.启动所有persistent属性为true的应用
                startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
                ....
            }
            
    }
    ....
    void startPersistentApps(int matchFlags) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;

        synchronized (this) {
            try {
                // 从PKMS的应用MAP中拿到所有具有FLAG_PERSISTENT标志位的应用
                final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
                for (ApplicationInfo app : apps) {
                    // 过滤掉包名为android的应用
                    if (!"android".equals(app.packageName)) {
                        //2. 添加并启动该APP进程
                        addAppLocked(app, null, false, null /* ABI override */);
                    }
                }
            } catch (RemoteException ex) {
            }
        }
    }
            
}

获得所有具有FLAG_PERSISTENT标志位的应用

platform/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

public class PackageManagerService extends IPackageManager.Stub
        implements PackageSender {
    ....
    // 存放所有应用的信息的Map
    final ArrayMap<String, PackageParser.Package> mPackages =
            new ArrayMap<String, PackageParser.Package>();
    ....
        
    @Override
    public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
            return ParceledListSlice.emptyList();
        }
        return new ParceledListSlice<>(getPersistentApplicationsInternal(flags));
    }

    private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
        final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();

        synchronized (mPackages) {
            final Iterator<PackageParser.Package> i = mPackages.values().iterator();
            final int userId = UserHandle.getCallingUserId();\
            // 遍历mPackages
            while (i.hasNext()) {
                final PackageParser.Package p = i.next();
                if (p.applicationInfo == null) continue;

                ....
                // 判断应用信息是否有FLAG_PERSISTENT标志位
                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) {
                            // 将应用的ApplicationInfo添加进列表
                            finalList.add(ai);
                        }
                    }
                }
            }
        }

        return finalList;
    }
}

添加并启动应用进程

AMS内有一个存放所有正在启动的persistent应用ListmPersistentStartingProcesses,后续在启动应用重启应用时都会使用到该List

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
        
    /**
     * 正在启动的persistent应用程序列表。
     */
    final ArrayList<ProcessRecord> mPersistentStartingProcesses = new ArrayList<ProcessRecord>();
    
    ....
    final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
            String abiOverride) {
        return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */,
                abiOverride);
    }
    
 final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
            boolean disableHiddenApiChecks, String abiOverride) {
        // ProcessRecord是用于描述进程的数据结构
        ProcessRecord app;
        // 传入的isolated为false
        if (!isolated) {
            // 第一次启动,这里查找应用所在的进程返回都为null
            app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
                    info.uid, true);
        } else {
            app = null;
        }
        if (app == null) {
            // 为应用创建ProcessRecord
            app = newProcessRecordLocked(info, customProcess, isolated, 0);
            updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        }
        ....
        
        if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
            app.persistent = true;
            app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
        }
        // 整个启动过程是异步的,所以这里仍需要判断应用线程是否为null,同时判断应用是否正在启动中(在mPersistentStartingProcesses列表内)
        if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
            // 应用没有在启动,则将应用添加到mPersistentStartingProcesses列表
            mPersistentStartingProcesses.add(app);
            // 启动应用
            startProcessLocked(app, "added application",
                    customProcess != null ? customProcess : app.processName, disableHiddenApiChecks,
                    abiOverride);
        }

        return app;
    }
    ....
}

系统启动时应用的ProcessRecord都未创建,所以在addAppLocked内首先通过newProcessRecordLocked为应用程序创建ProcessRecord,之后调用startProcessLocked来启动应用程序,启动的过程不是这部分的重点,就不再详细说明。

persistent应用启动完成

当应用启动完毕后就会调用到ActivityThread.java内的attach方法,方法内调用了AMSattachApplication方法,之后再到attachApplicationLocked,该方法内部就会将应用移除mPersistentStartingProcesses列表,表明应用启动完毕,同时为应用并注册一个死亡监听器AppDeathRecipient,用于应用被异常杀死后的重启。

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
        ....    

        private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
            ....
            final String processName = app.processName;
            try {
                AppDeathRecipient adr = new AppDeathRecipient(
                    app, pid, thread);
                thread.asBinder().linkToDeath(adr, 0);
                app.deathRecipient = adr;
            } catch (RemoteException e) {
                app.resetPackageList(mProcessStats);
                //如果注册死亡接收器失败,也会重新启动App进程
                startProcessLocked(app, "link fail", processName);
                return false;
            }
            ....
            // 将应用移除正在启动的持久性应用列表
            mPersistentStartingProcesses.remove(app);
            ....
        }
}

persistent应用死亡后重启

当应用被杀死后,就会调用死亡接收器AppDeathRecipientbinderDied方法,方法内根据应用是否是persistent应用来控制是否重启,整个流程如下:

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ....   
    private final class AppDeathRecipient implements IBinder.DeathRecipient {
        final ProcessRecord mApp;
        final int mPid;
        final IApplicationThread mAppThread;

        AppDeathRecipient(ProcessRecord app, int pid,
                IApplicationThread thread) {
            mApp = app;
            mPid = pid;
            mAppThread = thread;
        }

        @Override
        public void binderDied() {
            synchronized(ActivityManagerService.this) {
                // 1. 调用appDiedLocked
                appDiedLocked(mApp, mPid, mAppThread, true);
            }
        }
    }
    
    final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
            boolean fromBinderDied) {
        ....
        if (app.pid == pid && app.thread != null &&
                app.thread.asBinder() == thread.asBinder()) {
            ....
            // 2. 调用appDiedLocked
            handleAppDiedLocked(app, false, true);
            ....
        }
        ....
    }
    
    private final void handleAppDiedLocked(ProcessRecord app,
            boolean restarting, boolean allowRestart) {
        int pid = app.pid;
        // 3. 调用appDiedLocked
        boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
                false /*replacingPid*/);
        ....
    }
 
    private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
            boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
        ....
        // 判断应用是否是persistent应用
        if (!app.persistent || app.isolated) {
            // 如果不是persistent应用,则直接被清理掉
            ....
        } else if (!app.removed) {
            // 如果是persistent应用,则保留相应的信息
            // 判断其是否在待启动应用程序mPersistentStartingProcesses列表
            // 不在的话则添加,并设置restart为true
            if (mPersistentStartingProcesses.indexOf(app) < 0) {
                mPersistentStartingProcesses.add(app);
                restart = true;
            }
        }
        
        if (restart && !app.isolated) {
            // 重新启动我们的应用进程
            if (index < 0) {
                ProcessList.remove(app.pid);
            }
            addProcessNameLocked(app);
            app.pendingStart = false;
            // 启动应用程序进程
            startProcessLocked(app, "restart", app.processName);
            return true;
        } else if (app.pid > 0 && app.pid != MY_PID) {
            // 不需要重启的应用
            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);
        }
    }
}

经过这个过程之后,persistent属性为true的应用程序进程就会被重启。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容