自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android后臺(tái)殺死系列之二:ActivityManagerService與App現(xiàn)場(chǎng)恢復(fù)機(jī)制

移動(dòng)開發(fā) Android
本篇是Android后臺(tái)殺死系列的第二篇,主要講解ActivityMangerService是如何恢復(fù)被后臺(tái)殺死的進(jìn)程的(基于4.3 ),在開篇FragmentActivity及PhoneWindow后臺(tái)殺死處理機(jī)制 中,簡(jiǎn)述了后臺(tái)殺死所引起的一些常見問題,還有Android系統(tǒng)控件對(duì)后臺(tái)殺死所做的一些兼容,以及onSaveInstance跟onRestoreInstance的作用于執(zhí)行時(shí)機(jī),最后說了如何應(yīng)對(duì)后臺(tái)殺死,但是對(duì)于被后臺(tái)殺死的進(jìn)程如何恢復(fù)的并沒有講解,本篇不涉及后臺(tái)殺死,比如LowmemoryKiller機(jī)制,只講述被殺死的進(jìn)程如何恢復(fù)的。

  

本篇是Android后臺(tái)殺死系列的第二篇,主要講解ActivityMangerService是如何恢復(fù)被后臺(tái)殺死的進(jìn)程的(基于4.3 ),在開篇FragmentActivity及PhoneWindow后臺(tái)殺死處理機(jī)制 中,簡(jiǎn)述了后臺(tái)殺死所引起的一些常見問題,還有Android系統(tǒng)控件對(duì)后臺(tái)殺死所做的一些兼容,以及onSaveInstance跟onRestoreInstance的作用于執(zhí)行時(shí)機(jī),最后說了如何應(yīng)對(duì)后臺(tái)殺死,但是對(duì)于被后臺(tái)殺死的進(jìn)程如何恢復(fù)的并沒有講解,本篇不涉及后臺(tái)殺死,比如LowmemoryKiller機(jī)制,只講述被殺死的進(jìn)程如何恢復(fù)的。假設(shè),一個(gè)應(yīng)用被后臺(tái)殺死,再次從最近的任務(wù)列表喚起App時(shí)候,系統(tǒng)是如何處理的呢?有這么幾個(gè)問題可能需要解決:

  • Android框架層(AMS)如何知道App被殺死了
  • App被殺前的場(chǎng)景是如何保存的
  • 系統(tǒng)(AMS)如何恢復(fù)被殺的App
  • 被后臺(tái)殺死的App的啟動(dòng)流程跟普通的啟動(dòng)有什么區(qū)別
  • Activity的恢復(fù)順序?yàn)槭裁词堑剐蚧謴?fù)

系統(tǒng)(AMS)如何知道App被殺死了

首先來看第一個(gè)問題,系統(tǒng)如何知道Application被殺死了,Android使用了Linux的oomKiller機(jī)制,只是簡(jiǎn)單的做了個(gè)變種,采用分等級(jí)的LowmemoryKiller,但這個(gè)其實(shí)是內(nèi)核層面的,LowmemoryKiller殺死進(jìn)程后,不會(huì)像用戶空間發(fā)送通知,也就是說框架層的ActivityMangerService無法知道App是否被殺死,但是,只有知道App或者Activity是否被殺死,AMS(ActivityMangerService)才能正確的走喚起流程,那么AMS究竟是在什么時(shí)候知道App或者Activity被后臺(tái)殺死了呢?我們先看一下從最近的任務(wù)列表進(jìn)行喚起的時(shí)候,究竟發(fā)生了什么。

從最近的任務(wù)列表或者Icon再次喚起App的流程

在系統(tǒng)源碼systemUi的包里,有個(gè)RecentActivity,這個(gè)其實(shí)就是最近的任務(wù)列表的入口,而其呈現(xiàn)界面是通過RecentsPanelView來展現(xiàn)的,點(diǎn)擊最近的App其執(zhí)行代碼如下:

  1. public void handleOnClick(View view) { 
  2.     ViewHolder holder = (ViewHolder)view.getTag(); 
  3.     TaskDescription ad = holder.taskDescription; 
  4.     final Context context = view.getContext(); 
  5.     final ActivityManager am = (ActivityManager) 
  6.             context.getSystemService(Context.ACTIVITY_SERVICE); 
  7.     Bitmap bm = holder.thumbnailViewImageBitmap; 
  8.     ... 
  9.     // 關(guān)鍵點(diǎn) 1  如果TaskDescription沒有被主動(dòng)關(guān)閉,正常關(guān)閉,ad.taskId就是>=0 
  10.     if (ad.taskId >= 0) { 
  11.         // This is an active task; it should just go to the foreground. 
  12.         am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME, 
  13.                 opts); 
  14.     } else { 
  15.         Intent intent = ad.intent; 
  16.         intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 
  17.                 | Intent.FLAG_ACTIVITY_TASK_ON_HOME 
  18.                 | Intent.FLAG_ACTIVITY_NEW_TASK); 
  19.         try { 
  20.             context.startActivityAsUser(intent, opts, 
  21.                     new UserHandle(UserHandle.USER_CURRENT)); 
  22.         }... 
  23.  

在上面的代碼里面,有個(gè)判斷ad.taskId >= 0,如果滿足這個(gè)條件,就通過moveTaskToFront喚起APP,那么ad.taskId是如何獲取的?recent包里面有各類RecentTasksLoader,這個(gè)類就是用來加載最近任務(wù)列表的一個(gè)Loader,看一下它的源碼,主要看一下加載:

  1. @Override 
  2.        protected Void doInBackground(Void... params) { 
  3.            // We load in two stages: first, we update progress with just the first screenful 
  4.            // of items. Then, we update with the rest of the items 
  5.            final int origPri = Process.getThreadPriority(Process.myTid()); 
  6.            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 
  7.            final PackageManager pm = mContext.getPackageManager(); 
  8.            final ActivityManager am = (ActivityManager) 
  9.            mContext.getSystemService(Context.ACTIVITY_SERVICE); 
  10.  
  11.            final List<ActivityManager.RecentTaskInfo> recentTasks = 
  12.                    am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE); 
  13.              
  14.            .... 
  15.                TaskDescription item = createTaskDescription(recentInfo.id, 
  16.                        recentInfo.persistentId, recentInfo.baseIntent, 
  17.                        recentInfo.origActivity, recentInfo.description); 
  18.            .... 
  19.            }   

可以看到,其實(shí)就是通過ActivityManger的getRecentTasks向AMS請(qǐng)求最近的任務(wù)信息,然后通過createTaskDescription創(chuàng)建TaskDescription,這里傳遞的recentInfo.id其實(shí)就是TaskDescription的taskId,來看一下它的意義:

  1. public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, 
  2.         int flags, int userId) { 
  3.         ...            
  4.         IPackageManager pm = AppGlobals.getPackageManager(); 
  5.  
  6.         final int N = mRecentTasks.size(); 
  7.         ... 
  8.         for (int i=0; i<N && maxNum > 0; i++) { 
  9.             TaskRecord tr = mRecentTasks.get(i); 
  10.             if (i == 0 
  11.                     || ((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0) 
  12.                     || (tr.intent == null
  13.                     || ((tr.intent.getFlags() 
  14.                             &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) { 
  15.                 ActivityManager.RecentTaskInfo rti 
  16.                         = new ActivityManager.RecentTaskInfo(); 
  17.                 rti.id = tr.numActivities > 0 ? tr.taskId : -1; 
  18.                 rti.persistentId = tr.taskId; 
  19.                 rti.baseIntent = new Intent( 
  20.                         tr.intent != null ? tr.intent : tr.affinityIntent); 
  21.                 if (!detailed) { 
  22.                     rti.baseIntent.replaceExtras((Bundle)null); 
  23.                 }  

可以看出RecentTaskInfo的id是由TaskRecord決定的,如果TaskRecord中numActivities > 0就去TaskRecord的Id,否則就取-1,這里的numActivities其實(shí)就是TaskRecode中記錄的ActivityRecord的數(shù)目,更具體的細(xì)節(jié)可以自行查看ActivityManagerService及ActivityStack,那么這里就容易解釋了,只要是存活的APP、或者被LowmemoryKiller殺死的APP,其AMS的ActivityRecord是完整保存的,這就是恢復(fù)的依據(jù)。RecentActivity獲取的數(shù)據(jù)其實(shí)就是AMS中的翻版,RecentActivity并不知道將要喚起的APP是否是存活的,只要TaskRecord告訴RecentActivity是存貨的,那么久直接走喚起流程,也就是通過ActivityManager的moveTaskToFront喚起App,至于后續(xù)的工作,就完全交給AMS來處理?,F(xiàn)看一下到這里的流程圖: 

 

 

 

在喚起App的時(shí)候AMS偵測(cè)App或者Activity是否被異常殺死

接著往下看moveTaskToFrontLocked,這個(gè)函數(shù)在ActivityStack中,ActivityStack主要用來管理ActivityRecord棧的,所有start的Activity都在ActivityStack中保留一個(gè)ActivityRecord,這個(gè)也是AMS管理Activity的一個(gè)依據(jù),ActivityStack最終moveTaskToFrontLocked會(huì)調(diào)用resumeTopActivityLocked來喚起Activity,AMS獲取即將resume的Activity信息的方式主要是通過ActivityRecord,它并不知道Activity本身是否存活,獲取之后,AMS知道喚醒Activity的環(huán)節(jié)才知道App或者Activity被殺死,具體看一下resumeTopActivityLocked源碼:

  1. final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { 
  2.    
  3.      // This activity is now becoming visible. 
  4.         mService.mWindowManager.setAppVisibility(next.appToken, true); 
  5.                 
  6.      ....    恢復(fù)邏輯   
  7.     if (next.app != null && next.app.thread != null) { 
  8.       // 正?;謴?fù) 
  9.         try { 
  10.             // Deliver all pending results. 
  11.             ArrayList a = next.results; 
  12.             if (a != null) { 
  13.                 final int N = a.size(); 
  14.                 if (!next.finishing && N > 0) { 
  15.                     next.app.thread.scheduleSendResult(next.appToken, a); 
  16.                 } 
  17.             } 
  18.             ... 
  19.             next.app.thread.scheduleResumeActivity(next.appToken, 
  20.                     mService.isNextTransitionForward());  
  21.             ... 
  22.         } catch (Exception e) { 
  23.             // Whoops, need to restart this activity! 
  24.             // 這里需要重啟,難道被后臺(tái)殺死,走的是異常分支嗎???? 異常殺死 
  25.             if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to " 
  26.                     + lastState + ": " + next); 
  27.             next.state = lastState; 
  28.             mResumedActivity = lastResumedActivity; 
  29.             <!--確實(shí)這里是因?yàn)檫M(jìn)程掛掉了--> 
  30.             Slog.i(TAG, "Restarting because process died: " + next); 
  31.              。。。 
  32.             startSpecificActivityLocked(nexttruefalse); 
  33.             return true
  34.         } 
  35.         ... 
  36.         }  

由于沒有主動(dòng)調(diào)用finish的,所以AMS并不會(huì)清理掉ActivityRecord與TaskRecord ,因此resume的時(shí)候走的就是上面的分支,可以這里會(huì)調(diào)用next.app.thread.scheduleSendResult或者next.app.thread.scheduleResumeActivity進(jìn)行喚起上一個(gè)Activity,但是如果APP或者Activity被異常殺死,那么喚起的操作一定是失敗,會(huì)拋出異常,首先假設(shè)APP整個(gè)被殺死,那么APP端同AMS通信的Binder線程也不復(fù)存在,這個(gè)時(shí)候通過Binder進(jìn)行通信就會(huì)拋出RemoteException,如此,就會(huì)走下面的catch部分,通過startSpecificActivityLocked再次將APP重建,并且將最后的Activity重建,其實(shí)你可以本地利用AIDL寫一個(gè)C/S通信,在將一端關(guān)閉,然后用另一端訪問,就會(huì)拋出RemoteException異常,如下圖: 

 

 

 

還有一種可能,APP沒有被kill,但是Activity被Kill掉了,這個(gè)時(shí)候會(huì)怎么樣?首先,Activity的管理是一定通過AMS的,Activity的kill一定是是AMS操刀的,是有記錄的,嚴(yán)格來說,這種情況并不屬于后臺(tái)殺死,因?yàn)檫@屬于AMS正常的管理,在可控范圍,比如打開了開發(fā)者模式中的“不保留活動(dòng)”,這個(gè)時(shí)候,雖然會(huì)殺死Activity,但是仍然保留了ActivitRecord,所以再喚醒,或者回退的的時(shí)候仍然有跡可循,看一下ActivityStack的Destroy回調(diào)代碼,

  1. final boolean destroyActivityLocked(ActivityRecord r, 
  2.             boolean removeFromApp, boolean oomAdj, String reason) { 
  3.         ... 
  4.         if (hadApp) { 
  5.           ... 
  6.            boolean skipDestroy = false
  7.             try { 
  8.              關(guān)鍵代碼 1 
  9.                 r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing, 
  10.                         r.configChangeFlags); 
  11.              ... 
  12.             if (r.finishing && !skipDestroy) { 
  13.                 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r 
  14.                         + " (destroy requested)"); 
  15.                 r.state = ActivityState.DESTROYING; 
  16.                 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG); 
  17.                 msg.obj = r; 
  18.                 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT); 
  19.             } else { 
  20.           關(guān)鍵代碼 2 
  21.                 r.state = ActivityState.DESTROYED; 
  22.                 if (DEBUG_APP) Slog.v(TAG, "Clearing app during destroy for activity " + r); 
  23.                 r.app = null
  24.             } 
  25.         }  
  26.         return removedFromHistory; 
  27.     }   

這里有兩個(gè)關(guān)鍵啊你單,1是告訴客戶端的AcvitityThread清除Activity,2是標(biāo)記如果AMS自己非正常關(guān)閉的Activity,就將ActivityRecord的state設(shè)置為ActivityState.DESTROYED,并且清空它的ProcessRecord引用:r.app = null。這里是喚醒時(shí)候的一個(gè)重要標(biāo)志,通過這里AMS就能知道Activity被自己異常關(guān)閉了,設(shè)置ActivityState.DESTROYED是為了讓避免后面的清空邏輯。

  1. final void activityDestroyed(IBinder token) { 
  2.     synchronized (mService) { 
  3.         final long origId = Binder.clearCallingIdentity(); 
  4.         try { 
  5.             ActivityRecord r = ActivityRecord.forToken(token); 
  6.             if (r != null) { 
  7.                 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r); 
  8.             } 
  9.            int index = indexOfActivityLocked(r); 
  10.             if (index >= 0) { 
  11.             1  <!--這里會(huì)是否從history列表移除ActivityRecord--> 
  12.                 if (r.state == ActivityState.DESTROYING) { 
  13.                     cleanUpActivityLocked(r, truefalse); 
  14.                     removeActivityFromHistoryLocked(r); 
  15.                 } 
  16.             } 
  17.             resumeTopActivityLocked(null); 
  18.         } finally { 
  19.             Binder.restoreCallingIdentity(origId); 
  20.         } 
  21.     } 
  22.  

看代碼關(guān)鍵點(diǎn)1,只有r.state == ActivityState.DESTROYING的時(shí)候,才會(huì)移除ActivityRecord,但是對(duì)于不非正常finish的Activity,其狀態(tài)是不會(huì)被設(shè)置成ActivityState.DESTROYING,是直接跳過了ActivityState.DESTROYING,被設(shè)置成了ActivityState.DESTROYED,所以不會(huì)removeActivityFromHistoryLocked,也就是保留了ActivityRecord現(xiàn)場(chǎng),好像也是依靠異常來區(qū)分是否是正常的結(jié)束掉Activity。這種情況下是如何啟動(dòng)Activity的呢? 通過上面兩點(diǎn)分析,就知道了兩個(gè)關(guān)鍵點(diǎn)

  1. ActivityRecord沒有動(dòng)HistoryRecord列表中移除
  2. ActivityRecord 的ProcessRecord字段被置空,r.app = null

這樣就保證了在resumeTopActivityLocked的時(shí)候,走startSpecificActivityLocked分支

  1. final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { 
  2.           ... 
  3.               
  4.         if (next.app != null && next.app.thread != null) {  
  5.         ... 
  6.          
  7.         } else { 
  8.             // Whoops, need to restart this activity! 
  9.           ... 
  10.             startSpecificActivityLocked(nexttruetrue); 
  11.         } 
  12.  
  13.         return true
  14.     }  

到這里,AMS就知道了這個(gè)APP或者Activity是不是被異常殺死過,從而,決定是走resume流程還是restore流程。

App被殺前的場(chǎng)景是如何保存的: 新Activity啟動(dòng)跟舊Activity的保存

App現(xiàn)場(chǎng)的保存流程相對(duì)是比較簡(jiǎn)單的,入口基本就是startActivity的時(shí)候,只要是界面的跳轉(zhuǎn)基本都牽扯到Activity的切換跟當(dāng)前Activity場(chǎng)景的保存:先畫個(gè)簡(jiǎn)單的圖形,開偏里面講FragmentActivity的時(shí)候,簡(jiǎn)單說了一些onSaveInstance的執(zhí)行時(shí)機(jī),這里詳細(xì)看一下AMS是如何管理這些跳轉(zhuǎn)以及場(chǎng)景保存的,模擬場(chǎng)景:Activity A 啟動(dòng)Activity B的時(shí)候,這個(gè)時(shí)候A不可見,可能會(huì)被銷毀,需要保存A的現(xiàn)場(chǎng),這個(gè)流程是什么樣的:簡(jiǎn)述如下

  • ActivityA startActivity ActivityB
  • ActivityA pause
  • ActivityB create
  • ActivityB start
  • ActivityB resume
  • ActivityA onSaveInstance
  • ActivityA stop

流程大概是如下樣子: 

 

 

 

現(xiàn)在我們通過源碼一步一步跟一下,看看AMS在新Activity啟動(dòng)跟舊Activity的保存的時(shí)候,到底做了什么:跳過簡(jiǎn)單的startActivity,直接去AMS中去看

ActivityManagerService

  1. public final int startActivityAsUser(IApplicationThread caller, String callingPackage, 
  2.         Intent intent, String resolvedType, IBinder resultTo, 
  3.         String resultWho, int requestCode, int startFlags, 
  4.         String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) { 
  5.     enforceNotIsolatedCaller("startActivity"); 
  6.      ... 
  7.     return mMainStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, 
  8.             resultTo, resultWho, requestCode, startFlags, profileFile, profileFd, 
  9.             nullnull, options, userId); 
  10.  

ActivityStack

  1. final int startActivityMayWait(IApplicationThread caller, int callingUid, 
  2.                    
  3.         int res = startActivityLocked(caller, intent, resolvedType, 
  4.                 aInfo, resultTo, resultWho, requestCode, callingPid, callingUid, 
  5.                 callingPackage, startFlags, options, componentSpecified, null); 
  6.          
  7.      。。。 
  8. }   

這里通過startActivityMayWait啟動(dòng)新的APP,或者新Activity,這里只看簡(jiǎn)單的,至于從桌面啟動(dòng)App的流程,可以去參考更詳細(xì)的文章,比如老羅的startActivity流程,大概就是新建ActivityRecord,ProcessRecord之類,并加入AMS中相應(yīng)的堆棧等,resumeTopActivityLocked是界面切換的統(tǒng)一入口,第一次進(jìn)來的時(shí)候,由于ActivityA還在沒有pause,因此需要先暫停ActivityA,這些完成后,

ActivityStack

  1. final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {        
  2.    ... 
  3.    <!--必須將當(dāng)前Resume的Activity設(shè)置為pause 然后stop才能繼續(xù)--> 
  4.  // We need to start pausing the current activity so the top one 
  5.   // can be resumed... 
  6.   if (mResumedActivity != null) {             
  7.       if (next.app != null && next.app.thread != null) { 
  8.            
  9.           mService.updateLruProcessLocked(next.app, false); 
  10.       } 
  11.       startPausingLocked(userLeaving, false); 
  12.       return true
  13.       } 
  14.       ....  

其實(shí)這里就是暫停ActivityA,AMS通過Binder告訴ActivityThread需要暫停的ActivityA,ActivityThread完成后再通過Binder通知AMS,AMS會(huì)開始resume ActivityB,

  1. private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) { 
  2.  
  3.     if (prev.app != null && prev.app.thread != null) { 
  4.        ... 
  5.         try { 
  6.             prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing, 
  7.                     userLeaving, prev.configChangeFlags);  

ActivityThread

  1. private void handlePauseActivity(IBinder token, boolean finished, 
  2.             boolean userLeaving, int configChanges) { 
  3.         ActivityClientRecord r = mActivities.get(token); 
  4.         if (r != null) { 
  5.             ... 
  6.             performPauseActivity(token, finished, r.isPreHoneycomb()); 
  7.             ... 
  8.             // Tell the activity manager we have paused. 
  9.             try { 
  10.                 ActivityManagerNative.getDefault().activityPaused(token); 
  11.             } catch (RemoteException ex) { 
  12.             } 
  13.         } 
  14.     }  

AMS收到ActivityA發(fā)送過來的pause消息之后,就會(huì)喚起ActivityB,入口還是resumeTopActivityLocked,喚醒B,之后還會(huì)A給進(jìn)一步stop掉,這個(gè)時(shí)候就牽扯到現(xiàn)場(chǎng)的保存,

ActivityStack

  1. private final void completePauseLocked() { 
  2.    
  3.    if (!mService.isSleeping()) { 
  4.        resumeTopActivityLocked(prev); 
  5.    } else { 
  6.     
  7.   ... 
  8.     

ActivityB如何啟動(dòng)的,本文不關(guān)心,只看ActivityA如何保存現(xiàn)場(chǎng)的,ActivityB起來后,會(huì)通過ActivityStack的stopActivityLocked去stop ActivityA,

  1. private final void stopActivityLocked(ActivityRecord r) { 
  2.        ... 
  3.         if (mMainStack) { 
  4.               
  5.             r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags); 
  6.         ... 
  7.        }  

回看APP端,看一下ActivityThread中的調(diào)用:首先通過callActivityOnSaveInstanceState,將現(xiàn)場(chǎng)保存到Bundle中去,

  1. private void performStopActivityInner(ActivityClientRecord r, 
  2.         StopInfo info, boolean keepShown, boolean saveState) { 
  3.        ... 
  4.         // Next have the activity save its current state and managed dialogs... 
  5.         if (!r.activity.mFinished && saveState) { 
  6.             if (r.state == null) { 
  7.                 state = new Bundle(); 
  8.                 state.setAllowFds(false); 
  9.                 mInstrumentation.callActivityOnSaveInstanceState(r.activity, state); 
  10.                 r.state = state; 
  11.          。。。 
  12.          }  

之后,通過ActivityManagerNative.getDefault().activityStopped,通知AMS Stop動(dòng)作完成,在通知的時(shí)候,還會(huì)將保存的現(xiàn)場(chǎng)數(shù)據(jù)帶過去。

  1. private static class StopInfo implements Runnable { 
  2.     ActivityClientRecord activity; 
  3.     Bundle state; 
  4.     Bitmap thumbnail; 
  5.     CharSequence description; 
  6.  
  7.     @Override public void run() { 
  8.         // Tell activity manager we have been stopped. 
  9.         try { 
  10.  
  11.             ActivityManagerNative.getDefault().activityStopped( 
  12.                 activity.token, state, thumbnail, description); 
  13.         } catch (RemoteException ex) { 
  14.         } 
  15.     } 
  16.  

通過上面流程,AMS不僅啟動(dòng)了新的Activity,同時(shí)也將上一個(gè)Activity的現(xiàn)場(chǎng)進(jìn)行了保存,及時(shí)由于種種原因上一個(gè)Actiivity被殺死,在回退,或者重新喚醒的過程中AMS也能知道如何喚起Activiyt,并恢復(fù)。

現(xiàn)在解決兩個(gè)問題,1、如何保存現(xiàn)場(chǎng),2、AMS怎么判斷知道APP或者Activity是否被異常殺死,那么就剩下最后一個(gè)問題了,AMS如何恢復(fù)被異常殺死的APP或者Activity呢。

整個(gè)Application被后臺(tái)殺死情況下的恢復(fù)邏輯

其實(shí)在講解AMS怎么判斷知道APP或者Activity是否被異常殺死的時(shí)候,就已經(jīng)涉及了恢復(fù)的邏輯,也知道了一旦AMS知道了APP被后臺(tái)殺死了,那就不是正常的resuem流程了,而是要重新laucher,先來看一下整個(gè)APP被干掉的會(huì)怎么處理,看resumeTopActivityLocked部分,從上面的分析已知,這種場(chǎng)景下,會(huì)因?yàn)锽inder通信拋異常走異常分支,如下:

  1. final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { 
  2.   .... 
  3.   if (next.app != null && next.app.thread != null) { 
  4.             if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next); 
  5.             ...             
  6.             try { 
  7.              ... 
  8.             } catch (Exception e) { 
  9.                 // Whoops, need to restart this activity! 
  10.                 這里是知道整個(gè)app被殺死的 
  11.                 Slog.i(TAG, "Restarting because process died: " + next); 
  12.                 next.state = lastState; 
  13.                 mResumedActivity = lastResumedActivity; 
  14.                 Slog.i(TAG, "Restarting because process died: " + next); 
  15.                
  16.                 startSpecificActivityLocked(nexttruefalse); 
  17.                 return true
  18.             }  

從上面的代碼可以知道,其實(shí)就是走startSpecificActivityLocked,這根第一次從桌面喚起APP沒多大區(qū)別,只是有一點(diǎn)需要注意,那就是這種時(shí)候啟動(dòng)的Activity是有上一次的現(xiàn)場(chǎng)數(shù)據(jù)傳遞過得去的,因?yàn)樯洗卧谕说胶笈_(tái)的時(shí)候,所有Activity界面的現(xiàn)場(chǎng)都是被保存了,并且傳遞到AMS中去的,那么這次的恢復(fù)啟動(dòng)就會(huì)將這些數(shù)據(jù)返回給ActivityThread,再來仔細(xì)看一下performLaunchActivity里面關(guān)于恢復(fù)的特殊處理代碼:

  1. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
  2. ActivityInfo aInfo = r.activityInfo; 
  3.      Activity activity = null
  4.     try { 
  5.         java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); 
  6.         activity = mInstrumentation.newActivity( 
  7.                 cl, component.getClassName(), r.intent); 
  8.         StrictMode.incrementExpectedActivityCount(activity.getClass()); 
  9.         r.intent.setExtrasClassLoader(cl); 
  10.         if (r.state != null) { 
  11.             r.state.setClassLoader(cl); 
  12.         } 
  13.     } catch (Exception e) { 
  14.      ... 
  15.     } 
  16.      try { 
  17.         Application app = r.packageInfo.makeApplication(false, mInstrumentation); 
  18.             ... 
  19.              關(guān)鍵點(diǎn) 1  
  20.             mInstrumentation.callActivityOnCreate(activity, r.state); 
  21.             ... 
  22.             r.activity = activity; 
  23.             r.stopped = true
  24.             if (!r.activity.mFinished) { 
  25.                 activity.performStart(); 
  26.                 r.stopped = false
  27.             } 
  28.             關(guān)鍵點(diǎn) 1  
  29.             if (!r.activity.mFinished) { 
  30.                 if (r.state != null) { 
  31.                     mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); 
  32.                 } 
  33.             } 
  34.             if (!r.activity.mFinished) { 
  35.                 activity.mCalled = false
  36.                 mInstrumentation.callActivityOnPostCreate(activity, r.state); 
  37.             ... 
  38.  
  39. } 

看一下關(guān)鍵點(diǎn)1跟2,先看關(guān)鍵點(diǎn)1,mInstrumentation.callActivityOnCreate會(huì)回調(diào)Actiivyt的onCreate,這個(gè)函數(shù)里面其實(shí)主要針對(duì)FragmentActivity做一些Fragment恢復(fù)的工作,ActivityClientRecord中的r.state是AMS傳給APP用來恢復(fù)現(xiàn)場(chǎng)的,正常啟動(dòng)的時(shí)候,這些都是null。再來看關(guān)鍵點(diǎn)2 ,在r.state != null非空的時(shí)候執(zhí)行mInstrumentation.callActivityOnRestoreInstanceState,這個(gè)函數(shù)默認(rèn)主要就是針對(duì)Window做一些恢復(fù)工作,比如ViewPager恢復(fù)之前的顯示位置等,也可以用來恢復(fù)用戶保存數(shù)據(jù)。

Application沒有被后臺(tái)殺死,Activity被殺死的恢復(fù)

打開開發(fā)者模式”不保留活動(dòng)“,就是這種場(chǎng)景,在上面的分析中,知道,AMS主動(dòng)異常殺死Activity的時(shí)候,將AcitivityRecord的app字段置空,因此resumeTopActivityLocked同整個(gè)APP被殺死不同,會(huì)走下面的分支

  1. final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { 
  2.      ... 
  3.          
  4.     if (next.app != null && next.app.thread != null) {  
  5.         ... 
  6.          
  7.     } else { 
  8.             關(guān)鍵點(diǎn) 1 只是重啟Activity,可見這里其實(shí)是知道的,進(jìn)程并沒死, 
  9.         // Whoops, need to restart this activity! 
  10.          
  11.         startSpecificActivityLocked(nexttruetrue); 
  12.     } 
  13.  
  14.     return true
  15.  

雖然不太一樣,但是同樣走startSpecificActivityLocked流程,只是不新建APP進(jìn)程,其余的都是一樣的,不再講解。到這里,我們應(yīng)該就了解了,

  • Android是如何在預(yù)防的情況下保存場(chǎng)景
  • AMS如何知道APP是否被后臺(tái)殺死
  • AMS如何根據(jù)ActivityStack重建APP被殺死時(shí)的場(chǎng)景

到這里ActivityManagerService恢復(fù)APP場(chǎng)景的邏輯就應(yīng)該講完了。再碎碎念一些問題,可能是一些面試的點(diǎn)。

  • 主動(dòng)清除最近任務(wù)跟異常殺死的區(qū)別:ActivityStack是否正常清楚
  • 恢復(fù)的時(shí)候,為什么是倒序恢復(fù):因?yàn)檫@是ActivityStack中的HistoryRecord中棧的順序,嚴(yán)格按照AMS端來
  • 一句話概括Android后臺(tái)殺死恢復(fù)原理:Application進(jìn)程被Kill,但現(xiàn)場(chǎng)被AMS保存,AMS能根據(jù)保存恢復(fù)Application現(xiàn)場(chǎng)
責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2017-01-12 14:21:25

AndroidFragmentActFragment

2010-05-11 14:37:56

MySQL 備份

2010-05-21 18:15:41

MySQL 備份

2010-11-04 09:43:15

虛擬備份

2014-06-23 17:04:25

2019-09-11 11:38:30

MySQLInnoDB數(shù)據(jù)庫(kù)

2022-03-04 15:43:36

文件管理模塊Harmony鴻蒙

2019-09-11 09:37:17

數(shù)據(jù)庫(kù)MySQL系統(tǒng)

2011-11-28 12:55:37

JavaJVM

2023-08-07 06:39:03

網(wǎng)絡(luò)傳輸

2023-12-25 09:26:51

監(jiān)控系統(tǒng)工具

2013-05-20 17:04:09

2013-03-04 13:27:43

2015-05-06 10:16:59

2022-02-17 19:47:03

安卓ANR故障

2018-04-17 14:20:45

物聯(lián)網(wǎng)發(fā)展趨勢(shì)互聯(lián)網(wǎng)

2011-10-17 15:03:48

2011-11-17 15:28:02

2009-09-04 13:09:06

IT職業(yè)規(guī)劃喻勇

2021-11-08 15:06:15

鴻蒙HarmonyOS應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)