多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > 說說Android應用的persistent屬性

說說Android應用的persistent屬性

來源:程序員人生   發布時間:2015-01-07 08:18:35 閱讀次數:9234次

說說Android利用的persistent屬性

 

侯 亮

 

 

1 啟動persistent利用

    在Android系統中,有1種永久性利用。它們對應的AndroidManifest.xml文件里,會將persistent屬性設為true,比如:

<application android:name="PhoneApp" android:persistent="true" android:label="@string/dialerIconLabel" android:icon="@drawable/ic_launcher_phone">


    在系統啟動之時,AMS的systemReady()會加載所有persistent為true的利用。

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; i++) { ApplicationInfo info = (ApplicationInfo)apps.get(i); if(info != null&& !info.packageName.equals("android")) { addAppLocked(info,false); } } } } catch(RemoteException ex) { // pm is in same process, this will never happen. }

其中的STOCK_PM_FLAGS的定義以下:

// 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;


上面代碼中的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 = 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; }

     在PKMS中,有1個記錄所有的程序包信息的哈希表(mPackages),每一個表項中含有ApplicationInfo信息,該信息的flags(int型)數據中有1個專門的bit用于表示persistent。getPersistentApplications()函數會遍歷這張表,找出所有persistent包,并返回ArrayList<ApplicationInfo>。


     從代碼里可以看出,帶persistent標志的系統利用(即flags中設置了FLAG_SYSTEM)是1定會被選上的,但如果不是系統利用的話,則要進1步判斷當前是不是處于“安全模式”,1旦處于安全模式,那末就算利用設置了persistent屬性,也不會被選中。

     隨后systemReady()開始遍歷選中的ApplicationInfo,并對包名不為“android”的結點履行addAppLocked()。addAppLocked()的代碼以下:

<pre name="code" class="java">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; }


?
    在AMS中,所謂的“add App”主要是指“添加1個與App進程對應的ProcessRecord節點”。固然,如果該節點已添加過了,那末是不會重復添加的。在添加節點的動作完成以后,addAppLocked()還會檢查App進程是不是已啟動好了,如果還沒有開始啟動,此時就會調用startProcessLocked()啟動這個進程。既然addAppLocked()試圖確認App“正在正常運作”或“將被正常啟動”,那末其對應的package就不可能處于stopped狀態,這就是上面代碼調用setPackageStoppedState(...,false,...)的意思。


    現在,我們就清楚了,那些persistent屬性為true的利用,基本上都是在系統啟動伊始就啟動起來的。

    由于啟動進程的進程是異步的,所以我們需要1個緩沖列表(即上面代碼中的mPersistentStartingProcesses列表)來記錄那些“正處于啟動狀態,而又沒有啟動終了的”ProcessRecord結點。1旦目標進程啟動終了后,目標進程會attach系統,因而走到AMS的attachApplicationLocked(),在這個函數里,會把目標進程對應的ProcessRecord結點從mPersistentStartingProcesses緩沖列表里刪除。

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

?

2 如何保證利用的持久性(persistent)

    我們知道,persistent1詞的意思是“持久”,那末persistent利用的意思又是甚么呢?簡單地說,這類利用會固執地運行于系統當中,從系統1啟動,1直到系統關機。

    為了保證這類持久性,persistent利用必須能夠在異常出現時,自動重新啟動。在Android里是這樣實現的。每一個ActivityThread中會有1個專門和AMS通訊的binder實體――final ApplicationThread mAppThread。這個實體在AMS中對應的代理接口為IApplicationThread。

    當AMS履行到attachApplicationLocked()時,會針對目標用戶進程的IApplicationThread接口,注冊1個binder訃告監聽器,1旦往后用戶進程意外掛掉,AMS就可以在第1時間感知到,并采取相應的措施。如果AMS發現意外掛掉的利用是persistent的,它會嘗試重新啟動這個利用。

    注冊訃告監聽器的代碼以下:

AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread); thread.asBinder().linkToDeath(adr,0); app.deathRecipient = adr;

其中的thread就是IApplicationThread代理。

    AppDeathRecipient的定義以下:

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

當其監聽的binder實體死亡時,系統會回調AppDeathRecipient的binderDied()。這個回調函數會展轉重啟persistent利用,調用關系以下:



    1般情況下,當1個利用進程掛掉后,AMS固然會清算掉其對應的ProcessRecord,這就是cleanUpApplicationRecordLocked()的主要工作。但是,對persistent利用,cleanUpApplicationRecordLocked()會嘗試再次啟動對應的利用進程。代碼截選以下:

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) { . . . . . . } . . . . . . }

    現在我們可以畫1張關于“啟動persistent利用”的示意圖:


 

3 補充知識點

3.1 persistent利用可以在系統未準備好時啟動

    在AMS中,有1個isAllowedWhileBooting()函數,其代碼以下:

boolean isAllowedWhileBooting(ApplicationInfo ai) { return (ai.flags & ApplicationInfo.FLAG_PERSISTENT) != 0; }

    從這個函數可以看到,將persistent屬性設為true的利用,是允許在boot的進程中啟動的。我們可以查看前文提到的startProcessLocked()函數:

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

?

其中的最后幾句可以改寫為以下更容易理解的情勢:

if (mProcessesReady || isAllowedWhileBooting(info) || allowWhileBooting) { startProcessLocked(app, hostingType, hostingNameStr); return (app.pid != 0) ? app : null; } else { . . . . . . returnapp; }

?

    也就是說,當系統已處于以下幾種情況時,多參數的startProcessLocked()會進1步調用另外一個只有3個參數的startProcessLocked():
1)系統已處于ready狀態;
2)想要啟動persistent利用;
3)參數中明確指定可以在boot進程中啟動利用。

    補充說1下,1般情況下,當AMS調用startProcessLocked()時,傳入的allowWhileBooting參數都為false。比如說,當系統需要啟動“某個content provider或某個service或某個特定activity”時,此時傳給startProcessLocked()的allowWhileBooting參數是寫死為false的。只有1種特殊情況下會在該參數中傳入true,那就是當系統發出的廣播intent中攜帶有Intent.FLAG_RECEIVER_BOOT_UPGRADE標記時,此時允許在系統未ready時,啟動接受廣播的目標進程。

4 結束

    有關Android利用的persistent屬性,我們就先說這么多。希望對大家有點兒幫助。

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 小说区 图片区 | 青青自拍视频一区二区三区 | 老年人一级特黄aa大片 | 在线播放网站 | 日韩欧美高清 | 在线欧美69v免费观看视频 | a丫久久久久久一级毛片 | 色妞影视| 亚洲永久精品免费www52zcm男男 | 欧美激情亚洲精品日韩1区2区 | 理伦三级 | 被男人吃奶添下面好舒服视频 | 最新国产视频 | 视频三区精品中文字幕 | 一区二区免费视频 | 日本怡春院欧美一区二区三区 | 国产精品免费视频一区二区 | 亚洲视频 中文字幕 | 欧美一区二区三区在线观看不卡 | 欧美亚洲国产一区二区三区 | 性高跟鞋xxxxhd | 欧美一区二区三区在线可观看 | 欧美精品 在线观看 | 福利午夜影院 | 在线观看视频h | 欧美精品福利 | 国内精品伊人久久大香线焦 | 欧美金妇欧美乱妇xxxx | 欧美日韩在线播一区二区三区 | 亚洲欧美色综合一区二区在线 | 欧美1区二区三区公司 | 亚洲欧美一区二区久久 | 欧美乱码 | 2020狠狠操 | 在线观看三级视频 | 在线观看视频免费播放 | 色播成人网 | 国产中文99视频在线观看 | freexxxx性香港hd性 | 禁视频网站在线观看漫画 | 欧美日韩一区二区三区久久 |