首页 > 代码库 > 说说Android应用的persistent属性
说说Android应用的persistent属性
在Android系统中,有一种永久性应用。它们对应的AndroidManifest.xml文件里,会将persistent属性设为true,比如:
?
1 | </application> |
在系统启动之时,AMS的systemReady()会加载所有persistent为true的应用。
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | public void systemReady( final Runnable goingCallback) { . . . . . . . . . . . . try { List apps = AppGlobals.getPackageManager(). getPersistentApplications(STOCK_PM_FLAGS); if (apps != null ) { intN = apps.size(); inti; for (i= 0 ; i<n; applicationinfo= "" happen.= "" in= "" info= "" is= "" never= "" pm= "" pre= "" remoteexception= "" same= "" this = "" will= "" ><p> </p><p> 其中的STOCK_PM_FLAGS的定义如下:</p><p> </p><pre class = "brush:java;" > // The flags that are set for all calls we make to the package manager. static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;</pre> <p> </p> <br> <p>上面代码中的getPersistentApplications()函数的定义如下:</p> <p> </p> <pre class = "brush:java;" > public List getPersistentApplications( int flags) { final ArrayList finalList = new ArrayList(); // reader synchronized (mPackages) { final Iterator<packageparser. package > i = mPackages.values().iterator(); final int userId = UserId.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); finalList.add(PackageParser.generateApplicationInfo(p, flags, ps != null ? ps.getStopped(userId) : false , ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, userId)); } } } return finalList; }</packageparser. package ></applicationinfo></applicationinfo></applicationinfo></pre> <br> <p> </p> 在PKMS中,有一个记录所有的程序包信息的哈希表(mPackages),每个表项中含有ApplicationInfo信息,该信息的flags( int 型)数据中有一个专门的bit用于表示persistent。getPersistentApplications()函数会遍历这张表,找出所有persistent包,并返回ArrayList。 <p> </p> <p>从代码里可以看出,带persistent标志的系统应用(即flags中设置了FLAG_SYSTEM)是一定会被选上的,但如果不是系统应用的话,则要进一步判断当前是否处于“安全模式”,一旦处于安全模式,那么就算应用设置了persistent属性,也不会被选中。</p> <p>随后systemReady()开始遍历选中的ApplicationInfo,并对包名不为“android”的结点执行addAppLocked()。addAppLocked()的代码如下:</p> <p> </p> <pre class = "brush:java;" ></pre> <pre class = "java" name= "code" > final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(info.processName, info.uid); } else { app = null ; } if (app == null ) { app = newProcessRecordLocked( null , info, null , isolated); mProcessNames.put(info.processName, app.uid, app); if (isolated) { mIsolatedProcesses.put(app.uid, app); } updateLruProcessLocked(app, true , true ); } // This package really, really can not be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( info.packageName, false, UserId.getUserId(app.uid)); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, Failed trying to unstop package + info.packageName + : + e); } if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) { app.persistent = true; app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; } if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); startProcessLocked(app, added application, app.processName); } return app; }</pre> <p> </p> <pre class = "brush:java;" ></pre> <p> </p> ? 在AMS中,所谓的“add App”主要是指“添加一个与App进程对应的ProcessRecord节点”。当然,如果该节点已经添加过了,那么是不会重复添加的。在添加节点的动作完成以后,addAppLocked()还会检查App进程是否已经启动好了,如果尚未开始启动,此时就会调用startProcessLocked()启动这个进程。既然addAppLocked()试图确认App“正在正常运作”或者“将被正常启动”,那么其对应的 package 就不可能处于stopped状态,这就是上面代码调用setPackageStoppedState(..., false ,...)的意思。 <p> </p> <p>现在,我们就清楚了,那些persistent属性为 true 的应用,基本上都是在系统启动伊始就启动起来的。</p> <p>因为启动进程的过程是异步的,所以我们需要一个缓冲列表(即上面代码中的mPersistentStartingProcesses列表)来记录那些“正处于启动状态,而又没有启动完毕的”ProcessRecord结点。一旦目标进程启动完毕后,目标进程会attach系统,于是走到AMS的attachApplicationLocked(),在这个函数里,会把目标进程对应的ProcessRecord结点从mPersistentStartingProcesses缓冲列表里删除。</p> <p> </p> <pre class = "brush:java;" > private final boolean attachApplicationLocked(IApplicationThread thread, intpid) { // Find the application record that is being attached... either via // the pid if we are running in multiple processes, or just pull the // next app record if we are emulating process with anonymous threads. ProcessRecord app; . . . . . . thread.asBinder().linkToDeath(adr, 0 ); . . . . . . thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, profileFile, profileFd, profileAutoStop, app.instrumentationArguments, app.instrumentationWatcher, testMode, enableOpenGlTrace, isRestrictedBackupMode || !normalMode, app.persistent, newConfiguration(mConfiguration), app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); . . . . . . . . . . . . // Remove this record from the list of starting applications. mPersistentStartingProcesses.remove(app); . . . . . .</pre> <p> </p> ? <h1> 2 如何保证应用的持久性(persistent)</h1> <p>我们知道,persistent一词的意思是“持久”,那么persistent应用的意思又是什么呢?简单地说,这种应用会顽固地运行于系统之中,从系统一启动,一直到系统关机。</p> <p>为了保证这种持久性,persistent应用必须能够在异常出现时,自动重新启动。在Android里是这样实现的。每个ActivityThread中会有一个专门和AMS通信的binder实体—— final ApplicationThread mAppThread。这个实体在AMS中对应的代理接口为IApplicationThread。</p> <p>当AMS执行到attachApplicationLocked()时,会针对目标用户进程的IApplicationThread接口,注册一个binder讣告监听器,一旦日后用户进程意外挂掉,AMS就能在第一时间感知到,并采取相应的措施。如果AMS发现意外挂掉的应用是persistent的,它会尝试重新启动这个应用。</p> <p>注册讣告监听器的代码如下:</p> <p> </p> <pre class = "brush:java;" >AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread); thread.asBinder().linkToDeath(adr, 0 ); app.deathRecipient = adr;</pre> <p> </p> <p>其中的thread就是IApplicationThread代理。</p> <p>AppDeathRecipient的定义如下:</p> <p> </p> <pre class = "brush:java;" > private final class AppDeathRecipient implementsIBinder.DeathRecipient { final ProcessRecord mApp; final int mPid; final IApplicationThread mAppThread; AppDeathRecipient(ProcessRecord app, intpid, IApplicationThread thread) { if (localLOGV) Slog.v(TAG,New death recipient + this + for thread + thread.asBinder()); mApp = app; mPid = pid; mAppThread = thread; } publicvoidbinderDied() { if (localLOGV) Slog.v(TAG,Death received in + this + for thread + mAppThread.asBinder()); synchronized (ActivityManagerService. this ) { appDiedLocked(mApp, mPid, mAppThread); } } }</pre> <br> <p> </p> <p>当其监听的binder实体死亡时,系统会回调AppDeathRecipient的binderDied()。这个回调函数会辗转重启persistent应用,调用关系如下:</p> <p><img alt= "\" src="http://www.mamicode.com/ http: //www.2cto.com/uploadfile/Collfiles/20150104/20150104091208196.gif" style="width: 544px; height: 370px;"></p> <p> </p> <p>一般情况下,当一个应用进程挂掉后,AMS当然会清理掉其对应的ProcessRecord,这就是cleanUpApplicationRecordLocked()的主要工作。然而,对于persistent应用,cleanUpApplicationRecordLocked()会尝试再次启动对应的应用进程。代码截选如下:</p> <p> </p> <pre class = "brush:java;" > private final void cleanUpApplicationRecordLocked(ProcessRecord app, boolean restarting, boolean allowRestart, int index) { . . . . . . . . . . . . if (!app.persistent || app.isolated) { . . . . . . mProcessNames.remove(app.processName, app.uid); mIsolatedProcesses.remove(app.uid); . . . . . . } else if (!app.removed) { if (mPersistentStartingProcesses.indexOf(app) < 0 ) { mPersistentStartingProcesses.add(app); restart = true ; } } . . . . . . . . . . . . if (restart && !app.isolated) { mProcessNames.put(app.processName, app.uid, app); startProcessLocked(app,restart, app.processName); } else if (app.pid > 0 && app.pid != MY_PID) { . . . . . . } . . . . . . }</pre> <br> <p> </p> <p>现在我们可以画一张关于“启动persistent应用”的示意图:</p> <p><img alt= "\" src="http://www.mamicode.com/ http: //www.2cto.com/uploadfile/Collfiles/20150104/20150104091209197.gif" style="width: 623px; height: 385px;"></p> <p> </p> <h1> 3 补充知识点</h1> <h2> 3.1 persistent应用可以在系统未准备好时启动</h2> <p>在AMS中,有一个isAllowedWhileBooting()函数,其代码如下:</p> <pre class = "brush:java;" > boolean isAllowedWhileBooting(ApplicationInfo ai) { return (ai.flags & ApplicationInfo.FLAG_PERSISTENT) != 0 ; } </pre> <p>从这个函数可以看到,将persistent属性设为 true 的应用,是允许在boot的过程中启动的。我们可以查看前文提到的startProcessLocked()函数:</p> <p> </p> <pre class = "brush:java;" > final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(processName, info.uid); } else { // If this is an isolated process, it can‘t re-use an existing process. app = null ; } . . . . . . . . . . . . if (!mProcessesReady && !isAllowedWhileBooting(info) && !allowWhileBooting) { if (!mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } if (DEBUG_PROCESSES) Slog.v(TAG, System not ready, putting on hold: + app); return app; } startProcessLocked(app, hostingType, hostingNameStr); return (app.pid != 0 ) ? app : null ; }</pre> <p> </p> ? <p>其中的最后几句可以改写为以下更易理解的形式:</p> <p> </p> <pre class = "brush:java;" > if (mProcessesReady || isAllowedWhileBooting(info) || allowWhileBooting) { startProcessLocked(app, hostingType, hostingNameStr); return (app.pid != 0 ) ? app : null ; } else { . . . . . . returnapp; }</pre> <br> <p> </p> ?<br> <br> <p>也就是说,当系统已经处于以下几种情况时,多参数的startProcessLocked()会进一步调用另一个只有三个参数的startProcessLocked():<br> 1 )系统已经处于ready状态;<br> 2 )想要启动persistent应用;<br> 3 )参数中明确指定可以在boot过程中启动应用。</p> <p>补充说一下,一般情况下,当AMS调用startProcessLocked()时,传入的allowWhileBooting参数都为 false 。比如说,当系统需要启动“某个content provider或者某个service或者某个特定activity”时,此时传给startProcessLocked()的allowWhileBooting参数是写死为 false 的。只有一种特殊情况下会在该参数中传入 true ,那就是当系统发出的广播intent中携带有Intent.FLAG_RECEIVER_BOOT_UPGRADE标记时,此时允许在系统未ready时,启动接受广播的目标进程。</p> <h1> </h1> </applicationinfo></n;> |
结伴旅游,一个免费的交友网站:www.jieberu.com
推推族,免费得门票,游景区:www.tuituizu.com
说说Android应用的persistent属性
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。