Android persistent屬性原理分析

以下代碼基于Android9.0

persistent屬性的定義

開(kāi)發(fā)系統(tǒng)應(yīng)用時(shí),有時(shí)我們需要應(yīng)用常駐,被殺死后能夠自動(dòng)重啟家夺,此時(shí)就需要使用到persistent屬性,
下面是關(guān)于該屬性在framework層的定義疤坝,屬性的定義位于
persistent屬性定義在platform/frameworks/base/core/res/res/values/attrs_manifest.xml文件內(nèi):

    <!-- 控制應(yīng)用程序是否處于特殊持久模式的標(biāo)志,通常情況下不應(yīng)該被使用,該標(biāo)志位能夠保證應(yīng)用程序一直運(yùn)行 -->
    <attr name="persistent" format="boolean" />

persistent屬性的使用

開(kāi)發(fā)系統(tǒng)應(yīng)用時(shí)亲雪,有時(shí)我們需要應(yīng)用常駐勇凭,被殺死后能夠自動(dòng)重啟,此時(shí)我們就要在應(yīng)用的AndroidManifest.xml中設(shè)置

android:persistent="true"

設(shè)置后應(yīng)用就具備了以下兩個(gè)特性:

  1. 系統(tǒng)啟動(dòng)時(shí)該應(yīng)用也會(huì)啟動(dòng)
  2. 應(yīng)用被殺死后义辕,系統(tǒng)會(huì)重啟該應(yīng)用

persistent屬性的原理

persistent屬性的解析

當(dāng)我們應(yīng)用安裝或啟動(dòng)的過(guò)程中虾标,會(huì)對(duì)AndroidManifest.xml進(jìn)行解析,解析相關(guān)的代碼位于
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);
                ....
                // 獲取所設(shè)置的 persistent 值灌砖,默認(rèn)為 false
                if (sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
                    false)) {
                // 檢查應(yīng)用是否支持這個(gè)權(quán)限
                final String requiredFeature = sa.getNonResourceString(com.android.internal.R.styleable
                    .AndroidManifestApplication_persistentWhenFeatureAvailable);
                    if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) {
                        // 將 persistent 的 flag 設(shè)置到應(yīng)用信息中
                        ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
                    }
                }
                ....
    }
    ....
    
}

解析后就會(huì)將應(yīng)用的各種信息保存在PKMS中的一個(gè)存儲(chǔ)所有應(yīng)用信息的一個(gè)Map中璧函,其中設(shè)置了persistent的應(yīng)用就包含了ApplicationInfo.FLAG_PERSISTENT標(biāo)志位,之后在系統(tǒng)的啟動(dòng)過(guò)程中就會(huì)根據(jù)這個(gè)標(biāo)志位控制應(yīng)用的啟動(dòng)基显。

persistent應(yīng)用的啟動(dòng)

persistent應(yīng)用的啟動(dòng)發(fā)生在AMSsystemReady方法內(nèi)蘸吓,這一部分通過(guò)PKMS獲取到所有persistent為true的應(yīng)用列表,之后對(duì)列表進(jìn)行遍歷撩幽,通過(guò)addAppLocked方法將應(yīng)用一個(gè)個(gè)啟動(dòng)起來(lái)库继。
對(duì)應(yīng)代碼的位于
/platform/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ....
    // 該靜態(tài)常量用于判斷應(yīng)用是否persistent應(yīng)用
    private static final int PERSISTENT_MASK =
            ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
            
    // 當(dāng)系統(tǒng)服務(wù)啟動(dòng)時(shí),AMS執(zhí)行systemReady方法
    public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
            ....
            synchronized (this) {
                // 1.啟動(dòng)所有persistent屬性為true的應(yīng)用
                startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
                ....
            }
            
    }
    ....
    void startPersistentApps(int matchFlags) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;

        synchronized (this) {
            try {
                // 從PKMS的應(yīng)用MAP中拿到所有具有FLAG_PERSISTENT標(biāo)志位的應(yīng)用
                final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
                for (ApplicationInfo app : apps) {
                    // 過(guò)濾掉包名為android的應(yīng)用
                    if (!"android".equals(app.packageName)) {
                        //2. 添加并啟動(dòng)該APP進(jìn)程
                        addAppLocked(app, null, false, null /* ABI override */);
                    }
                }
            } catch (RemoteException ex) {
            }
        }
    }
            
}

獲得所有具有FLAG_PERSISTENT標(biāo)志位的應(yīng)用

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

public class PackageManagerService extends IPackageManager.Stub
        implements PackageSender {
    ....
    // 存放所有應(yīng)用的信息的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;

                ....
                // 判斷應(yīng)用信息是否有FLAG_PERSISTENT標(biāo)志位
                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) {
                            // 將應(yīng)用的ApplicationInfo添加進(jìn)列表
                            finalList.add(ai);
                        }
                    }
                }
            }
        }

        return finalList;
    }
}

添加并啟動(dòng)應(yīng)用進(jìn)程

AMS內(nèi)有一個(gè)存放所有正在啟動(dòng)的persistent應(yīng)用ListmPersistentStartingProcesses摸航,后續(xù)在啟動(dòng)應(yīng)用重啟應(yīng)用時(shí)都會(huì)使用到該List制跟。

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
        
    /**
     * 正在啟動(dòng)的persistent應(yīng)用程序列表。
     */
    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是用于描述進(jìn)程的數(shù)據(jù)結(jié)構(gòu)
        ProcessRecord app;
        // 傳入的isolated為false
        if (!isolated) {
            // 第一次啟動(dòng)酱虎,這里查找應(yīng)用所在的進(jìn)程返回都為null
            app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
                    info.uid, true);
        } else {
            app = null;
        }
        if (app == null) {
            // 為應(yīng)用創(chuàng)建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;
        }
        // 整個(gè)啟動(dòng)過(guò)程是異步的雨膨,所以這里仍需要判斷應(yīng)用線程是否為null,同時(shí)判斷應(yīng)用是否正在啟動(dòng)中(在mPersistentStartingProcesses列表內(nèi))
        if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
            // 應(yīng)用沒(méi)有在啟動(dòng)读串,則將應(yīng)用添加到mPersistentStartingProcesses列表
            mPersistentStartingProcesses.add(app);
            // 啟動(dòng)應(yīng)用
            startProcessLocked(app, "added application",
                    customProcess != null ? customProcess : app.processName, disableHiddenApiChecks,
                    abiOverride);
        }

        return app;
    }
    ....
}

系統(tǒng)啟動(dòng)時(shí)應(yīng)用的ProcessRecord都未創(chuàng)建聊记,所以在addAppLocked內(nèi)首先通過(guò)newProcessRecordLocked為應(yīng)用程序創(chuàng)建ProcessRecord,之后調(diào)用startProcessLocked來(lái)啟動(dòng)應(yīng)用程序恢暖,啟動(dòng)的過(guò)程不是這部分的重點(diǎn)排监,就不再詳細(xì)說(shuō)明。

persistent應(yīng)用啟動(dòng)完成

當(dāng)應(yīng)用啟動(dòng)完畢后就會(huì)調(diào)用到ActivityThread.java內(nèi)的attach方法杰捂,方法內(nèi)調(diào)用了AMSattachApplication方法舆床,之后再到attachApplicationLocked,該方法內(nèi)部就會(huì)將應(yīng)用移除mPersistentStartingProcesses列表嫁佳,表明應(yīng)用啟動(dòng)完畢挨队,同時(shí)為應(yīng)用并注冊(cè)一個(gè)死亡監(jiān)聽(tīng)器AppDeathRecipient,用于應(yīng)用被異常殺死后的重啟蒿往。

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);
                //如果注冊(cè)死亡接收器失敗盛垦,也會(huì)重新啟動(dòng)App進(jìn)程
                startProcessLocked(app, "link fail", processName);
                return false;
            }
            ....
            // 將應(yīng)用移除正在啟動(dòng)的持久性應(yīng)用列表
            mPersistentStartingProcesses.remove(app);
            ....
        }
}

persistent應(yīng)用死亡后重啟

當(dāng)應(yīng)用被殺死后,就會(huì)調(diào)用死亡接收器AppDeathRecipientbinderDied方法瓤漏,方法內(nèi)根據(jù)應(yīng)用是否是persistent應(yīng)用來(lái)控制是否重啟腾夯,整個(gè)流程如下:

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. 調(diào)用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. 調(diào)用appDiedLocked
            handleAppDiedLocked(app, false, true);
            ....
        }
        ....
    }
    
    private final void handleAppDiedLocked(ProcessRecord app,
            boolean restarting, boolean allowRestart) {
        int pid = app.pid;
        // 3. 調(diào)用appDiedLocked
        boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
                false /*replacingPid*/);
        ....
    }
 
    private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
            boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
        ....
        // 判斷應(yīng)用是否是persistent應(yīng)用
        if (!app.persistent || app.isolated) {
            // 如果不是persistent應(yīng)用颊埃,則直接被清理掉
            ....
        } else if (!app.removed) {
            // 如果是persistent應(yīng)用,則保留相應(yīng)的信息
            // 判斷其是否在待啟動(dòng)應(yīng)用程序mPersistentStartingProcesses列表
            // 不在的話則添加蝶俱,并設(shè)置restart為true
            if (mPersistentStartingProcesses.indexOf(app) < 0) {
                mPersistentStartingProcesses.add(app);
                restart = true;
            }
        }
        
        if (restart && !app.isolated) {
            // 重新啟動(dòng)我們的應(yīng)用進(jìn)程
            if (index < 0) {
                ProcessList.remove(app.pid);
            }
            addProcessNameLocked(app);
            app.pendingStart = false;
            // 啟動(dòng)應(yīng)用程序進(jìn)程
            startProcessLocked(app, "restart", app.processName);
            return true;
        } else if (app.pid > 0 && app.pid != MY_PID) {
            // 不需要重啟的應(yīng)用
            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);
        }
    }
}

經(jīng)過(guò)這個(gè)過(guò)程之后班利,persistent屬性為true的應(yīng)用程序進(jìn)程就會(huì)被重啟。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跷乐,一起剝皮案震驚了整個(gè)濱河市肥败,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌愕提,老刑警劉巖馒稍,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異浅侨,居然都是意外死亡纽谒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門如输,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鼓黔,“玉大人,你說(shuō)我怎么就攤上這事不见“幕” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵稳吮,是天一觀的道長(zhǎng)缎谷。 經(jīng)常有香客問(wèn)我,道長(zhǎng)灶似,這世上最難降的妖魔是什么列林? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮酪惭,結(jié)果婚禮上希痴,老公的妹妹穿的比我還像新娘。我一直安慰自己春感,他們只是感情好砌创,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著鲫懒,像睡著了一般纺铭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刀疙,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音扫倡,去河邊找鬼谦秧。 笑死竟纳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疚鲤。 我是一名探鬼主播锥累,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼集歇!你這毒婦竟也來(lái)了桶略?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诲宇,失蹤者是張志新(化名)和其女友劉穎际歼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體姑蓝,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹅心,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纺荧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旭愧。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宙暇,靈堂內(nèi)的尸體忽然破棺而出输枯,到底是詐尸還是另有隱情,我是刑警寧澤占贫,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布桃熄,位于F島的核電站,受9級(jí)特大地震影響靶剑,放射性物質(zhì)發(fā)生泄漏蜻拨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一桩引、第九天 我趴在偏房一處隱蔽的房頂上張望缎讼。 院中可真熱鬧,春花似錦坑匠、人聲如沸血崭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)夹纫。三九已至,卻和暖如春设凹,著一層夾襖步出監(jiān)牢的瞬間舰讹,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工闪朱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留月匣,地道東北人钻洒。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像锄开,于是被迫代替她去往敵國(guó)和親素标。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容