必威体育Betway必威体育官网
当前位置:首页 > IT技术

谈谈Android中的persistent属性

时间:2019-10-26 01:42:15来源:IT技术作者:seo实验室小编阅读:77次「手机版」
 

persistent

在我们开发系统级的APP时,很有可能就会用persistent属性。当在Androidmanifest.xml中将persistent属性设置为true时,那么该App就会具有如下两个特性:

  • 在系统刚起来的时候,该App也会被启动起来

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

1. persistent属性的定义

persistent属性定义在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" />

官方解释:

是一个用于控制应用程序特殊持久模式的标志。通常情况下不应被应用程序使用,它要求系统始终保持应用程序的运行。

2. persistent属性的使用

persistent用在AndroidManifest.xml的application标签上:

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

</application>

默认值为false。

3. persistent属性的原理分析

下面我们就从源码的角度来分析persistent属性的工作原理。

备注:本文的源码是Android6.0,不同的Android版本可能略有所不同。

3.1 persistent属性的解析

属性的解析主要发生在App安装或者系统启动的时候,解析代码的位置在:

/frameworks/base/core/java/android/content/pm/Packageparser.java

深入到PackageParser.java的parseBaseApplication中:

   private boolean parseBaseApplication(Package owner, resources res,
            XmlPullParser parser, AttributeSet attrs, int flags, String[] outERROR)
        throws XmlPullParserException, IOException {

	final ApplicationInfo ai = owner.applicationInfo;
    final String pkgName = owner.applicationInfo.packageName;

    TypedArray sa = res.obtainAttributes(attrs,
            com.android.internal.R.styleable.AndroidManifestApplication);

	...省略...

		if ((flags&PARSE_IS_SYSTEM) != 0) {
	            if (sa.getBoolean(
	                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
	                    false)) {
	                ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
	            }
	        }

	...省略...
}

在解析完系统中App的包信息后,会将解析好的信息保存在PMS中的mPackages的map中,ApplicationInfo的flag中有一个bit位用于保存该App是否是persistent。

这里主要是将persistent的flag设置为ApplicationInfo.FLAG_PERSISTENT。

3.2 系统启动persistent为true的App

在系统启动时,会启动persistent属性为true的App,代码位置在:

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

在系统启动时,AMS中的systemReady()方法会将所有在AndroidManifest中设置了persistent为true的App进程拉起来。

深入到AMS的systemReady()方法中:

public void systemReady(final Runnable goingCallback) {

	...省略...

    synchronized (this) {
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            try {
                List apps = AppGlobals.getPackageManager().
                    getPersistentApplications(STOCK_PM_FLAGS);//注释1
                if (apps != null) {
                    int N = apps.size();
                    int i;
                    for (i=0; i<N; i++) {
                        ApplicationInfo info
                            = (ApplicationInfo)apps.get(i);
                        if (info != null &&
                                !info.packageName.equals("android")) {
                            addAppLocked(info, false, null /* ABI override */);//注释2
                        }
                    }
                }
            } catch (RemoteException ex) {
                // pm is in same process, this will never happen.
            }
        }
		...省略...
	}

	...省略...

注释说明:

注释1:调用PackageManagerServices的getPersistentApplications方法获取所有在AndroidManifest中设置了persistent属性为true的App

注释2:调用ActivityManagerServcies的addAppLocked方法去启动App

深入到PackageManagerServices的getPersistentApplications方法中:

public List<ApplicationInfo> getPersistentApplications(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
                    && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
                    && (!mSafeMode || isSystemApp(p))) {
                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;
}

getPersistentApplications方法会遍历mPackages中所有的App,从判断条件中可以看到只有当在解析persistent属性时,ApplicationInfo的flag设置成了FLAG_PERSISTENT,且是系统App;或者是在非安全模式下,才会被选中。

可以看出被选中的情形有两种:

  • 系统App,只要ApplicationInfo的flag设置成了FLAG_PERSISTENT

  • 第三方安装的App,不仅要ApplicationInfo的flag设置成了FLAG_PERSISTENT,还需要在非安全模式下

继续回到ActivityManagerServcies的addAppLocked方法中:

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);
    }

	//如果是系统App,且persistent属性为true,则异常死亡后会重启
    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;
}

在App启动完成后,会在activitythread中调用ActivityManagerService的attachApplicationLocked()方法,将该App从mPersistentStartingProcesses移除,并注册一个死亡讣告监听器AppDeathRecipient,用于在App异常被杀后的处理工作。

深入到ActivityManagerService的attachApplicationLocked()方法中:

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {

	...省略...

    final String processName = app.processName;
    try {
		//注册死亡讣告监听器AppDeathRecipient
        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;
    }

	...省略...
	// Remove this record from the list of starting applications.
    mPersistentStartingProcesses.remove(app);

	...省略...

到此,persistent属性为true的App在开机时就会启动,并且会注册死亡讣告监听器AppDeathRecipient。

3.3 系统重新启动被强制kill掉的带有persistent属性的App

上面可知,进程在启动时,会为App注册一个死亡讣告,当App被杀掉后,就会调用AppDeathRecipient的binderDied方法:

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);
        }
    }
}

binderDied又会调用appDiedLocked()方法:

final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
        boolean fromBinderDied) {

	...省略...
	 // Clean up already done if the process has been re-started.
    if (app.pid == pid && app.thread != null &&
            app.thread.asBinder() == thread.asBinder()) {
        boolean doLowMem = app.instrumentationClass == null;
        boolean doOomAdj = doLowMem;
        ...省略...

        handleAppDiedLocked(app, false, true);

        ...省略...
}

handleAppDiedLocked又会调用handleAppDiedLocked()方法:

private final void handleAppDiedLocked(ProcessRecord app,
        boolean restarting, boolean allowRestart) {
    int pid = app.pid;
    boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
            false /*replacingPid*/);

    ...省略...
}

继续调用cleanUpApplicationRecordLocked()方法:

private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
        boolean restarting, boolean allowRestart, int index, boolean replacingPid) {

	...省略...


	//非persistent的App被kill后,就会被清理掉
    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);
        }
        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;
        }
    }

	...省略...

	//通过这个判断添加决定是否重启App进程
	//通过前面的过滤,persistent属性的App,restart=true,!app.isolated=true
    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);
		//启动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;
}

到此,带有persistent属性为true的App,就会在强制kill掉进程后,还会重启。

重启persistent应用的调用关系图如下:

非常感谢您的耐心阅读,希望我的文章对您有帮助。欢迎点评、转发或分享给您的朋友或技术群。

文章最后发布于: 2019-06-02 18:36:17

相关阅读

Android中SQLite数据库介绍

SQLite简介 更多干货 分布式实战(干货) spring cloud 实战(干货) mybatis 实战(干货) spring boot 实战(干货) React

Android中BindService方式使用的理解

原文地址为:Android中BindService方式使用的理解最近学习了一下Android里面的Service的应用,在BindService部分小卡了一下,主要是开

splitter 控件属性及作用

splitter 控件的作用,一是可以作为分隔条来分隔窗口中的不同部位,二是可以对窗口不同部位的大小进行实时调整。 如何界面让添加的Sp

android8.0/android O 新特性

Android O 行为变更 Android O 除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更。本文重点介绍您应该了解并在

Android8.1HAL层开发

本文基于Android8.1源码。这里介绍的是一种简单HAL的写法与调用。我将会编写一个app直接调用HAL的接口,而HAL层代码将直接读写驱动

分享到:

栏目导航

推荐阅读

热门阅读