Android Persistent常駐內存分析

Persistent常駐內存分析

簡介

通過官方註釋我知道該屬性用於是否讓你的應用一直處於運行狀態(通常說的常駐內存)。設置android:persistent
屬性爲true的app具有如下特點:

  • 在系統啓動的時候會被系統啓動起來。
  • 在該app被強制殺掉後系統會重新啓動該app,這種情況只針對系統內置app,第三方安裝的app不會被重啓這個地方在9.0以後包括9.0我不知道是否還有效,看源碼我有點困惑

這裏我們分析的代碼是Android10.0的源碼。

使用

在AndroidManifest文件下的application標籤中添加 android:persistent=“true”,默認是false。

<application
    android:persistent="true|false">
</application>
源碼分析

分析過程中我們可以思考一個問題: 設置android:persistent屬性,一定需要是系統App才生效嗎?

首先,App的AndroidManifest解析是在frameworks/base/core/java/android/content/pm/PackageParser.java中,我們找到persistence屬性所在的地方。
persistentWhenFeatureAvailable這個屬性我們可以忽略,他爲null的時候也可以執行到下邊的屬性設置 ai.flags |= ApplicationInfo.FLAG_PERSISTENT。

  • 解析設置屬性

8.0以前包括8.0是判斷是不是系統應用的:

if ((flags&PARSE_IS_SYSTEM) != 0) {
            if (sa.getBoolean(
                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
                    false)) {
                // Check if persistence is based on a feature being present
                final String requiredFeature = sa.getNonResourceString(
                    com.android.internal.R.styleable.
                    AndroidManifestApplication_persistentWhenFeatureAvailable);
                if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) {
                    ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
                }
            }
        }

9.0以後包括9.0並沒有判斷:

if (sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_persistent,
                false)) {
            // Check if persistence is based on a feature being present
            final String requiredFeature = sa.getNonResourceString(com.android.internal.R.styleable
                    .AndroidManifestApplication_persistentWhenFeatureAvailable);
            if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) {
                ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
            }
        }
  • 系統啓動時
    我們知道Android中管理Activity的是AMS,而Activity又是應用界面的承載體,Activity是和用戶交互的組件,那麼講解應用啓動,必定要談到AMS,而android:persistent="true"標識着系統的自啓動應用,那麼這些應用也不例外應該在系統啓動的時候自啓動我們去查看下AMS。
//AMS中,SystemReady中調用startPersistentApps他的詳細代碼如下:
 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, null, false, null /* ABI override */,
                                ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
                    }
                }
            } catch (RemoteException ex) {
            }
        }
    }

我們可以看到getPersistentApplications是通過AppGlobals.getPackageManager調用的我們直接去查看PMS,最終找到PMS中getPersistentApplicationsInternal的實現裏邊判斷了是否是系統應用或者是否是安全模式,是的話纔會在系統啓動的時候自動拉起來:

    private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
        final ArrayList<ApplicationInfo> finalList = new ArrayList<>();
        // 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;
    }
  • 應用被殺死時被重新拉起時

在ActivityManagerService中AMS.startPersistentApps -> AMS.addAppLocked -> AMS.startProcessLocked -> ProcessList.startProcessLocked -> Process.start 調用鏈最後調用Process.start 通過socket通知zygote fork出新的進程,然後通過ActivityThread中的main方法啓動應用。

ActivityThread中調用attach方法最終調用到AMS中的attachApplicationLocked,會爲應用程序的binder註冊一個AppDeathRecipient死亡代理,其實就是AIDL中的IBinder.DeathRecipient,在attachApplicationLocked中綁定好應用之後,會把啓動的常駐內存應用進程從mPersistentStartingProcesses(緩存的正在啓動的常駐內存進程列表)移除掉。

//attachApplicationLocked 綁定應用前註冊死亡代理
try {
            AppDeathRecipient adr = new AppDeathRecipient(
                    app, pid, thread);
            thread.asBinder().linkToDeath(adr, 0);
            app.deathRecipient = adr;
        } catch (RemoteException e) {
            app.resetPackageList(mProcessStats);
            mProcessList.startProcessLocked(app,
                    new HostingRecord("link fail", processName),
                    ZYGOTE_POLICY_FLAG_EMPTY);
            return false;
        }
// Remove this record from the list of starting applications. mPersistentStartingProcesses.remove(app);
        
//是AMS中的一個內部類
private final class AppDeathRecipient implements IBinder.DeathRecipient {
        final ProcessRecord mApp;
        final int mPid;
        final IApplicationThread mAppThread;

        AppDeathRecipient(ProcessRecord app, int pid,
                IApplicationThread thread) {
            if (DEBUG_ALL) Slog.v(
                TAG, "New death recipient " + this
                 + " for thread " + thread.asBinder());
            mApp = app;
            mPid = pid;
            mAppThread = thread;
        }

        @Override
        public void binderDied() {
            if (DEBUG_ALL) Slog.v(
                TAG, "Death received in " + this
                + " for thread " + mAppThread.asBinder());
            synchronized(ActivityManagerService.this) {
                appDiedLocked(mApp, mPid, mAppThread, true);
            }
        }
    }

當應用死亡時會回調AppDeathRecipient中的binderDied方法,然後會執行AMS中的appDiedLocked -> handleAppDiedLocked 在handleAppDiedLocked中有個cleanUpApplicationRecordLocked對persistence的應用處理如下:

//如果正在啓動不處理
		if (restarting) {
            return false;
        }
		//如果應用不是常駐應用則移除進程
        if (!app.isPersistent() || app.isolated) {
            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                    "Removing non-persistent process during cleanup: " + app);
            if (!replacingPid) {
                mProcessList.removeProcessNameLocked(app.processName, app.uid, app);
            }
            mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
      
        } 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是常駐內存的,所以我們需要去保持他存活。如果他已經不存在於mPersistentStartingProcesses(正在啓動的app進程緩存列表)中了,把它添加進去,並標記restart = true,後邊重開進程,重新啓動
            if (mPersistentStartingProcesses.indexOf(app) < 0) {
                mPersistentStartingProcesses.add(app);
                restart = true;
            }
        }
        if ((DEBUG_PROCESSES || DEBUG_CLEANUP) && mProcessesOnHold.contains(app)) Slog.v(
                TAG_CLEANUP, "Clean-up removing on hold: " + app);
        mProcessesOnHold.remove(app);

        mAtmInternal.onCleanUpApplicationRecord(app.getWindowProcessController());
		//需要重啓則重新啓動
        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);
            }
            mProcessList.addProcessNameLocked(app);
            app.pendingStart = false;
            mProcessList.startProcessLocked(app,
                    new HostingRecord("restart", app.processName),
                    ZYGOTE_POLICY_FLAG_EMPTY);
            return true;
            //否則移除掉
        } else if (app.pid > 0 && app.pid != MY_PID) {
            // Goodbye!
            mPidsSelfLocked.remove(app);
            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);
        }
總結

系統版本 < 9.0設置時就會判斷是不是系統應用,系統版本 >= 9.0
設置時隨便設置;但是在啓動時既要判斷是不是系統應用又要判斷persistence是否爲true;死亡重新拉起時,並沒有看到判斷是否爲系統應用,在9.0之後在添加屬性時,也沒有對是不是系統應用判斷,普通應用也可以設置這個屬性了,所以9.0之後死亡重新拉起可能對普通應用也會有效,這個地方那個大佬可以說一下,在哪裏有對系統應用的處理,我沒找到

推薦

要看源碼的話推薦Android 官方的CodeSearch

參考

Persistence解析包含一些應用啓動的東西比較全
Persistence屬性解析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章