Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android進程絕殺技--forceStop

Android進程絕殺技--forceStop

編輯:關於android開發

Android進程絕殺技--forceStop


一.概述

1.1 引言

話說Android開源系統擁有著App不計其數,百家爭鳴,都想在這“大爭之世”尋得系統存活的一席之地。然則系統資源有限,如若都割據為王,再強勁的CPU也會忙不過來,再龐大的內存終會消耗殆盡,再大容量的電池續航終會昙花一現。

面對芸芸眾生,無盡變數,系統以不變應萬變,一招絕殺神技forceStop騰空出世,此處以adb指令的方式為例來說說其內部機理:


force-stop命令殺掉所有用戶空間下的包名pkgName相關的信息,也可以通過--user來指定用戶Id。 當執行上述am指令時,則會觸發調用Am.java的main()方法,接下來從main方法開始說起。

1.2 Am.main

[-> Am.java]

1.3 Am.run

[-> Am.java]

1.4 Am.onRun

[-> Am.java]


1.5 Am.runForceStop

[-> Am.java]

當不指定userId時,則默認為UserHandle.USER_ALL。

1.6 AMP.forceStopPackage

[-> ActivityManagerNative.java ::AMP]


1.7 AMN.onTransact

[-> ActivityManagerNative.java]

MP.forceStopPackage來運行在執行adb時所創建的進程,經過Binder Driver後,進入system_server進程的一個binder線程來執行AMN.forceStopPackage,從這開始的操作(包括當前操作)便都運行在system_server系統進程。

1.8 小節

進程絕殺技force-stop,並非任意app可直接調用, 否則App間可以相互停止對方,則豈非天下大亂。該方法的存在便是供系統差遣。一般地,點擊home彈出的清理用戶最近使用app采取的策略便是force-stop.

至於force-stop的觸發方式,除了adb的方式,還可通過獲取ActivityManager再調用其方法forceStopPackage(),不過這是@hide隱藏方法,同樣是需要具有FORCE_STOP_PACKAGES權限。雖然第三方普通app不能直接調用,但對於深入理解Android,還是很有必要知道系統是如何徹底清理進程的過程。接下來,進入AMS來深入探查force-stop的內部機理。

二. force-stop內部機理

2.1 AMS.forceStopPackage

[-> ActivityManagerService.java]


這裡有一個過程非常重要,那就是setPackageStoppedState()將包的狀態設置為stopped,那麼所有廣播都無法接收,除非帶有標記FLAG_INCLUDE_STOPPED_PACKAGES的廣播,系統默認的廣播幾乎都是不帶有該標志,也就意味著被force-stop的應用是無法通過建立手機網絡狀態或者亮滅的廣播來拉起進程。

當使用force stop方式來結束進程時, reason一般都是”from pid “ + callingPid. 當然也有另外,那就是AMS.clearApplicationUserData方法調用forceStopPackageLocked的reason為”clear data”.

2.2 AMS.forceStopPackageLocked

清理跟該包名相關的進程和四大組件之外,還會發送廣播ACTION_PACKAGE_RESTARTED,用於清理已注冊的alarm,notification信息。

2.3 AMS.forceStopPackageLocked

對於didSomething只指當方法中所有行為,則返回true.比如killPackageProcessesLocked(),只要殺過一個進程則代表didSomething為true.

該方法的主要功能:
1.Process:調用AMS.killPackageProcessesLocked()清理該package所涉及的進程;
2.Activity:調用ASS.finishDisabledPackageActivitiesLocked()清理該package所涉及的Activity;
3.Service:調用AS.bringDownDisabledPackageServicesLocked()清理該package所涉及的Service;
4.Provider:調用AMS.removeDyingProviderLocked()清理該package所涉及的Provider;
5.BroadcastRecevier:調用BQ.cleanupDisabledPackageReceiversLocked()清理該package所涉及的廣播

接下來,從這5個角度來分別說說force-stop的執行過程.

三. Process

3.1AMS.killPackageProcessesLocked

一般地force-stop會指定包名,該方法會遍歷當前所有運行中的進程mProcessNames,以下條件同時都不滿足的進程,則會成為被殺的目標進程:(也就是說滿足以下任一條件都可以免死)
1.persistent進程:
2.進程setAdj< minOomAdj(默認為-100):
3.非UserHandle.USER_ALL同時, 且進程的userId不相等:多用戶模型下,不同用戶下不能相互殺;
4.進程沒有依賴該packageName, 且進程的AppId不相等;
5.進程沒有依賴該packageName, 且該packageName沒有運行在該進程.


通俗地來說就是:

  • forceStop不殺系統persistent進程;
  • 當指定用戶userId時,不殺其他用戶空間的進程;


除此之外,以下情況則必然會成為被殺進程:


  • 進程已標記remove=true的進程,則會被殺;
  • 進程的pkgDeps中包含該packageName,則會被殺;
  • 進程的pkgList中包含該packageName,且該進程與包名所指定的AppId相等則會被殺;

進程的pkgList是在啟動組件或者創建進程的過程向該隊列添加的,代表的是該應用下有組件運行在該進程。那麼pkgDeps是指該進程所依賴的包名,調用ClassLoader的過程添加。

3.2 AMS.removeProcessLocked

該方法的主要功能:

  • 從mProcessNames,mPidsSelfLocked隊列移除該進程;
  • 移除進程啟動超時的消息PROC_START_TIMEOUT_MSG;
  • 調用app.kill()來殺進程會同時調用Process.kill和Process.killProcessGroup, 該過程詳見理解殺進程的實現原理
  • 調用handleAppDiedLocked()來清理進程相關的信息, 該過程詳見binderDied()過程分析


四. Activity

4.1ASS.finishDisabledPackageActivitiesLocked

[-> ActivityStackSupervisor.java]

4.2AS.finishDisabledPackageActivitiesLocked

[-> ActivityStack.java]

4.3 AS.finishActivityLocked

[-> ActivityStack.java]

4.3.1 AR.makeFinishingLocked

[-> ActivityRecord.java]

4.3.2ASS.requestVisibleBehindLocked

4.3.3TaskRecord.setFrontOfTask

[-> TaskRecord.java]

  • 將該Task中從底部往上查詢, 第一個處於非finishing狀態的ActivityRecord,則設置為根Activity(即r.frontOfTask = true),其他都為false;
  • 當所有的activity都處於finishing狀態,則把最底部的activity設置成跟Activity.


4.3.4AS.adjustFocusedActivityLocked

[-> ActivityStack.java]

4.3.5AS.finishCurrentActivityLocked

滿足下面其中之一的條件,則會執行finish以及destroy Activity.
1.模式為FINISH_IMMEDIATELY
2.模式為FINISH_AFTER_PAUSE, 且Activity狀態已處於PAUSED;
3.Activity的狀態為STOPPED或INITIALIZING.


4.3.6 AS.destroyActivityLocked

五. Service

5.1bringDownDisabledPackageServicesLocked

[-> ActiveServices.java]

5.2collectPackageServicesLocked

[-> ActiveServices.java]

該方法的主要功能就是收集該滿足條件service放入mTmpCollectionResults.

5.3 bringDownServiceLocked

[-> ActiveServices.java]

5.4unscheduleServiceRestartLocked

六. Provider

6.1PM.collectPackageProvidersLocked

[-> ProviderMap.java]

SHAPE \* MERGEFORMAT


  • 當userId= UserHandle.USER_ALL時, 則會mSingletonByClass和mProvidersByClassPerUser結構中查詢所有屬於該package的providers.
  • 當userId= UserHandle.USER_OWNER時,則會從mSingletonByClass和mProvidersByClassPerUser中userId相等的 數據結構中查詢所有屬於該package的providers.
  • 當userId不屬於上述兩者之一時,則會從mProvidersByClassPerUser中userId相等的查詢所有屬於該package的providers.


6.2 PM.collectPackageProvidersLocked

[-> ProviderMap.java]

6.3AMS.removeDyingProviderLocked

當其他app使用該provider, 且建立stable的連接, 那麼對於非persistent進程,則會由於依賴該provider的緣故而被殺.


七. Broadcast

7.1BQ.cleanupDisabledPackageReceiversLocked

[-> BroadcastQueue.java]

該方法主要功能:


  • 清理並行廣播隊列mParallelBroadcasts;
  • 清理有序廣播隊列mOrderedBroadcasts



7.2BR.cleanupDisabledPackageReceiversLocked

[-> BroadcastRecord.java]

八. Alarm和Notification

在前面[小節2.2]介紹到處理完forceStopPackageLocked(),緊接著便是發送廣播ACTION_PACKAGE_RESTARTED,經過Broadcast廣播分發,最終調用到注冊過該廣播的接收者。

8.1 Alarm清理

[-> AlarmManagerService.java]

調用AlarmManagerService中的removeLocked()方法,從mAlarmBatches和mPendingWhileIdleAlarms隊列中移除包所相關的alarm.

8.2 Notification清理

[-> NotificationManagerService.java]



mNotificationList隊列中移除包所相關的Notification.

九. 級聯誅殺

這裡就跟大家分享一段經歷吧,記得之前有BAT的某浏覽器大廠(具體名稱就匿了),浏覽器會因為另一個app被殺而導致自己無辜被牽連所殺,並懷疑是ROM定制化導致的bug,於是發郵件向我廠請教緣由。

遇到這個問題,首先將兩個app安裝到Google原生系統,結果是依然會被級聯誅殺,很顯然可以排除廠商ROM定制的緣故,按常理說bug應該可以讓app自行解決。出於好奇,幫他們進一步調查了下這個問題,發現並非無辜被殺,而是force-stop的級聯誅殺所導致的。

簡單來說就是App1調用了getClassLoader()來加載App2,那麼App1所運行的進程便會在其pkgDeps隊列中增加App2的包名,在前面[小節3.2]已經提到pkgDeps,殺進程的過程中會遍歷該隊列,當App2被forceStop所殺時,便是級聯誅殺App1。App1既然會調用App2的ClassLoader來加載其方法,那麼就建立了一定的聯系,這是Google有意賦予forceStop這個強力殺的功能。

這個故事是想告訴大家在插件化或者反射的過程中要注意這種情況,防止不必要的誤傷。接下來具體說說這個過程是如何建立依賴的。

9.1 CI.getClassLoader

[-> ContextImpl.java]

9.2 LA.getClassLoader

[-> LoadedApk.java]

9.3 AMS.addPackageDependency

調用ClassLoader來加載啟動包名時,則會將該包名加入到進程的pkgDeps。

十. 總結

forceStop的功能如下:

1.Process:調用AMS.killPackageProcessesLocked()清理該package所涉及的進程;

2.Activity:調用ASS.finishDisabledPackageActivitiesLocked()清理該package所涉及的Activity;

3.Service:調用AS.bringDownDisabledPackageServicesLocked()清理該package所涉及的Service;

4.Provider:調用AMS.removeDyingProviderLocked()清理該package所涉及的Provider;

5.BroadcastRecevier:調用BQ.cleanupDisabledPackageReceiversLocked()清理該package所涉及的廣播

6.發送廣播ACTION_PACKAGE_RESTARTED,用於停止已注冊的alarm,notification.


功能點歸納:
1.force-stop並不會殺persistent進程;
2.當app被force-stop後,無法接收到任何普通廣播,那麼也就常見的監聽手機網絡狀態的變化或者屏幕亮滅的廣播來拉起進程肯定是不可行;
3.當app被force-stop後,那麼alarm鬧鐘一並被清理,無法實現定時響起的功能;
4.app被force-stop後,四大組件以及相關進程都被一一剪除清理,即便多進程架構的app也無法拉起自己;
5.級聯誅殺:當app通過ClassLoader加載另一個app,則會在force-stop的過程中會被級聯誅殺;
6.生死與共:當app與另個app使用了shareuid,則會在force-stop的過程,任意一方被殺則另一方也被殺,建立起生死與共的強關系。


既然force-stop多次提到殺進程,那最後簡單說兩句關於保活:正確的保活姿態,應該是在用戶需要時保證千萬別被殺,用戶不需要時別強保活,一切以用戶為出發點。


  • 進程是否需要存活,系統上層有AMS來管理緩存進程和空進程,底層有LowMemoryKiller來根據系統可用內存的情況來管理進程是否存活,這樣的策略是從系統整體性角度考慮,為了是給用戶提供更好更流暢的用戶體驗。
  • 用戶需要的時候千萬別被殺:謹慎使用插件化和共享uid,除非願意接受級聯誅殺和生死與共的場景;還有就是提高自身app的穩定性,減少crash和anr的發生頻率,這才是正道。
  • 用戶不需要的時候別強保活:為了保活,多進程架構,利用各種小技巧來提升優先級等都是不可取的,一招force-stop足以干掉90%以上的保活策略,當然還有一些其他手段及漏洞來保活,系統層面往往還會采取一些特別的方法來禁止保活。博主曾經干過手機底層的性能與功耗優化工作,深知不少app的流氓行徑,嚴重系統的流暢度與手機續航能力。

為了Android有更好的用戶體驗,為了不影響手機系統性能,為了不降低手機續航能力,建議大家花更多時間精力在如何提高app的穩健性,如何優化app性能,共同打造Android的良好生態圈。


小米開放平台

小米生態 開放共贏


小米開放平台匯聚了小米所有對外開放的技術、服務,提供技術支持、統計分析、分發推廣、應用接入等全方位服務和支持,是小米為企業和個人開發者提供學習、交流、合作和服務的綜合性平台。我們的優勢:2億用戶基礎,提供多種服務類型,開放軟件、硬件多種平台能力,重磅打造開發者扶持計劃,助力開發者提升業務流量和收入。


小米開放平台重磅推出小米帳號接入有禮活動:自今日起至2016年12月31日前成功接入小米帳號即可獲得小米開放平台免費提供的平台資源(小米應用商店、小米卡包、小米推送vip、小米帳號聯盟等資源),機會不容錯過,我們期待您的加入!
活動報名地址:http://dev.xiaomi.com/console/hd/account.html?hmsr=it168%E5%8D%9A%E5%AE%A2&hmpl=&hmcu=&hmkw=&hmci=
官方QQ交流群:398616987

想了解更多?

那就快來關注我們

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved