精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Android后臺殺死系列之二:ActivityManagerService與App現場恢復機制

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

  

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

  • Android框架層(AMS)如何知道App被殺死了
  • App被殺前的場景是如何保存的
  • 系統(AMS)如何恢復被殺的App
  • 被后臺殺死的App的啟動流程跟普通的啟動有什么區別
  • Activity的恢復順序為什么是倒序恢復

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

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

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

在系統源碼systemUi的包里,有個RecentActivity,這個其實就是最近的任務列表的入口,而其呈現界面是通過RecentsPanelView來展現的,點擊最近的App其執行代碼如下:

  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.     // 關鍵點 1  如果TaskDescription沒有被主動關閉,正常關閉,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.  

在上面的代碼里面,有個判斷ad.taskId >= 0,如果滿足這個條件,就通過moveTaskToFront喚起APP,那么ad.taskId是如何獲取的?recent包里面有各類RecentTasksLoader,這個類就是用來加載最近任務列表的一個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.            }   

可以看到,其實就是通過ActivityManger的getRecentTasks向AMS請求最近的任務信息,然后通過createTaskDescription創建TaskDescription,這里傳遞的recentInfo.id其實就是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其實就是TaskRecode中記錄的ActivityRecord的數目,更具體的細節可以自行查看ActivityManagerService及ActivityStack,那么這里就容易解釋了,只要是存活的APP、或者被LowmemoryKiller殺死的APP,其AMS的ActivityRecord是完整保存的,這就是恢復的依據。RecentActivity獲取的數據其實就是AMS中的翻版,RecentActivity并不知道將要喚起的APP是否是存活的,只要TaskRecord告訴RecentActivity是存貨的,那么久直接走喚起流程,也就是通過ActivityManager的moveTaskToFront喚起App,至于后續的工作,就完全交給AMS來處理。現看一下到這里的流程圖: 

 

 

 

在喚起App的時候AMS偵測App或者Activity是否被異常殺死

接著往下看moveTaskToFrontLocked,這個函數在ActivityStack中,ActivityStack主要用來管理ActivityRecord棧的,所有start的Activity都在ActivityStack中保留一個ActivityRecord,這個也是AMS管理Activity的一個依據,ActivityStack最終moveTaskToFrontLocked會調用resumeTopActivityLocked來喚起Activity,AMS獲取即將resume的Activity信息的方式主要是通過ActivityRecord,它并不知道Activity本身是否存活,獲取之后,AMS知道喚醒Activity的環節才知道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.      ....    恢復邏輯   
  7.     if (next.app != null && next.app.thread != null) { 
  8.       // 正常恢復 
  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.             // 這里需要重啟,難道被后臺殺死,走的是異常分支嗎???? 異常殺死 
  25.             if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to " 
  26.                     + lastState + ": " + next); 
  27.             next.state = lastState; 
  28.             mResumedActivity = lastResumedActivity; 
  29.             <!--確實這里是因為進程掛掉了--> 
  30.             Slog.i(TAG, "Restarting because process died: " + next); 
  31.              。。。 
  32.             startSpecificActivityLocked(nexttruefalse); 
  33.             return true
  34.         } 
  35.         ... 
  36.         }  

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

 

 

 

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

  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.              關鍵代碼 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.           關鍵代碼 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.     }   

這里有兩個關鍵啊你單,1是告訴客戶端的AcvitityThread清除Activity,2是標記如果AMS自己非正常關閉的Activity,就將ActivityRecord的state設置為ActivityState.DESTROYED,并且清空它的ProcessRecord引用:r.app = null。這里是喚醒時候的一個重要標志,通過這里AMS就能知道Activity被自己異常關閉了,設置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  <!--這里會是否從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.  

看代碼關鍵點1,只有r.state == ActivityState.DESTROYING的時候,才會移除ActivityRecord,但是對于不非正常finish的Activity,其狀態是不會被設置成ActivityState.DESTROYING,是直接跳過了ActivityState.DESTROYING,被設置成了ActivityState.DESTROYED,所以不會removeActivityFromHistoryLocked,也就是保留了ActivityRecord現場,好像也是依靠異常來區分是否是正常的結束掉Activity。這種情況下是如何啟動Activity的呢? 通過上面兩點分析,就知道了兩個關鍵點

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

這樣就保證了在resumeTopActivityLocked的時候,走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就知道了這個APP或者Activity是不是被異常殺死過,從而,決定是走resume流程還是restore流程。

App被殺前的場景是如何保存的: 新Activity啟動跟舊Activity的保存

App現場的保存流程相對是比較簡單的,入口基本就是startActivity的時候,只要是界面的跳轉基本都牽扯到Activity的切換跟當前Activity場景的保存:先畫個簡單的圖形,開偏里面講FragmentActivity的時候,簡單說了一些onSaveInstance的執行時機,這里詳細看一下AMS是如何管理這些跳轉以及場景保存的,模擬場景:Activity A 啟動Activity B的時候,這個時候A不可見,可能會被銷毀,需要保存A的現場,這個流程是什么樣的:簡述如下

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

流程大概是如下樣子: 

 

 

 

現在我們通過源碼一步一步跟一下,看看AMS在新Activity啟動跟舊Activity的保存的時候,到底做了什么:跳過簡單的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啟動新的APP,或者新Activity,這里只看簡單的,至于從桌面啟動App的流程,可以去參考更詳細的文章,比如老羅的startActivity流程,大概就是新建ActivityRecord,ProcessRecord之類,并加入AMS中相應的堆棧等,resumeTopActivityLocked是界面切換的統一入口,第一次進來的時候,由于ActivityA還在沒有pause,因此需要先暫停ActivityA,這些完成后,

ActivityStack

  1. final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {        
  2.    ... 
  3.    <!--必須將當前Resume的Activity設置為pause 然后stop才能繼續--> 
  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.       ....  

其實這里就是暫停ActivityA,AMS通過Binder告訴ActivityThread需要暫停的ActivityA,ActivityThread完成后再通過Binder通知AMS,AMS會開始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發送過來的pause消息之后,就會喚起ActivityB,入口還是resumeTopActivityLocked,喚醒B,之后還會A給進一步stop掉,這個時候就牽扯到現場的保存,

ActivityStack

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

ActivityB如何啟動的,本文不關心,只看ActivityA如何保存現場的,ActivityB起來后,會通過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中的調用:首先通過callActivityOnSaveInstanceState,將現場保存到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動作完成,在通知的時候,還會將保存的現場數據帶過去。

  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不僅啟動了新的Activity,同時也將上一個Activity的現場進行了保存,及時由于種種原因上一個Actiivity被殺死,在回退,或者重新喚醒的過程中AMS也能知道如何喚起Activiyt,并恢復。

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

整個Application被后臺殺死情況下的恢復邏輯

其實在講解AMS怎么判斷知道APP或者Activity是否被異常殺死的時候,就已經涉及了恢復的邏輯,也知道了一旦AMS知道了APP被后臺殺死了,那就不是正常的resuem流程了,而是要重新laucher,先來看一下整個APP被干掉的會怎么處理,看resumeTopActivityLocked部分,從上面的分析已知,這種場景下,會因為Binder通信拋異常走異常分支,如下:

  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.                 這里是知道整個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.             }  

從上面的代碼可以知道,其實就是走startSpecificActivityLocked,這根第一次從桌面喚起APP沒多大區別,只是有一點需要注意,那就是這種時候啟動的Activity是有上一次的現場數據傳遞過得去的,因為上次在退到后臺的時候,所有Activity界面的現場都是被保存了,并且傳遞到AMS中去的,那么這次的恢復啟動就會將這些數據返回給ActivityThread,再來仔細看一下performLaunchActivity里面關于恢復的特殊處理代碼:

  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.              關鍵點 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.             關鍵點 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. } 

看一下關鍵點1跟2,先看關鍵點1,mInstrumentation.callActivityOnCreate會回調Actiivyt的onCreate,這個函數里面其實主要針對FragmentActivity做一些Fragment恢復的工作,ActivityClientRecord中的r.state是AMS傳給APP用來恢復現場的,正常啟動的時候,這些都是null。再來看關鍵點2 ,在r.state != null非空的時候執行mInstrumentation.callActivityOnRestoreInstanceState,這個函數默認主要就是針對Window做一些恢復工作,比如ViewPager恢復之前的顯示位置等,也可以用來恢復用戶保存數據。

Application沒有被后臺殺死,Activity被殺死的恢復

打開開發者模式”不保留活動“,就是這種場景,在上面的分析中,知道,AMS主動異常殺死Activity的時候,將AcitivityRecord的app字段置空,因此resumeTopActivityLocked同整個APP被殺死不同,會走下面的分支

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

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

  • Android是如何在預防的情況下保存場景
  • AMS如何知道APP是否被后臺殺死
  • AMS如何根據ActivityStack重建APP被殺死時的場景

到這里ActivityManagerService恢復APP場景的邏輯就應該講完了。再碎碎念一些問題,可能是一些面試的點。

  • 主動清除最近任務跟異常殺死的區別:ActivityStack是否正常清楚
  • 恢復的時候,為什么是倒序恢復:因為這是ActivityStack中的HistoryRecord中棧的順序,嚴格按照AMS端來
  • 一句話概括Android后臺殺死恢復原理:Application進程被Kill,但現場被AMS保存,AMS能根據保存恢復Application現場
責任編輯:龐桂玉 來源: segmentfault
相關推薦

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數據庫

2022-03-04 15:43:36

文件管理模塊Harmony鴻蒙

2025-08-18 07:32:23

2019-09-11 09:37:17

數據庫MySQL系統

2011-11-28 12:55:37

JavaJVM

2023-08-07 06:39:03

網絡傳輸

2023-12-25 09:26:51

監控系統工具

2013-03-04 13:27:43

2013-05-20 17:04:09

2022-02-17 19:47:03

安卓ANR故障

2018-04-17 14:20:45

物聯網發展趨勢互聯網

2015-05-06 10:16:59

2025-08-14 07:32:42

2011-10-17 15:03:48

2011-11-17 15:28:02

點贊
收藏

51CTO技術棧公眾號

果冻天美麻豆一区二区国产| 日韩专区一区二区| 91精品亚洲| 精品久久久久久久久久久院品网| 2018日日夜夜| 国产免费av高清在线| 国产美女av一区二区三区| 久久人人爽人人| 国产精品久久久久久成人| 色播一区二区| 欧美在线一区二区三区| 日韩在线观看a| 成人影视在线播放| 丁香婷婷深情五月亚洲| 国产精品美女无圣光视频| 欧美黄色免费观看| 欧美肥老太太性生活| 日韩成人av网| 下面一进一出好爽视频| av综合电影网站| 一区二区三区中文在线| 日本不卡高清视频一区| 开心激情综合网| 久久精品99国产精品日本| 97在线视频国产| 午夜精品一区二区三区视频| 久久综合亚洲| 亚洲黄色av女优在线观看 | 亚洲一区中文字幕在线观看| 黑人精品无码一区二区三区AV| 亚洲乱码电影| 中文字幕欧美精品日韩中文字幕| 超碰97在线资源站| 婷婷综合国产| 欧美一区二区三区婷婷月色| 天天操天天爽天天射| 国产不卡123| 亚洲精品大片www| 一区二区三区视频在线播放| 免费在线视频你懂得| 丁香一区二区三区| 91久久国产综合久久蜜月精品| 国产99久久久久久免费看| 国产欧美日韩亚洲一区二区三区| 欧美美最猛性xxxxxx| 欧美多人猛交狂配| 亚洲精品亚洲人成在线观看| 日韩大陆欧美高清视频区| 自拍视频第一页| 一区二区视频| 日韩精品中午字幕| 女王人厕视频2ⅴk| 亚洲一区 二区| 日韩精品在线网站| 午夜诱惑痒痒网| 国产中文欧美日韩在线| 91精品国产综合久久精品麻豆| 天天色综合社区| 51一区二区三区| 欧美在线观看你懂的| 日本男人操女人| 韩国精品主播一区二区在线观看| 91成人看片片| 奇米影视四色在线| 国产一区二区三区精品在线观看| 欧美久久高跟鞋激| 三级网站免费看| 国产伦乱精品| 亚洲乱码一区av黑人高潮| 大又大又粗又硬又爽少妇毛片| 亚洲日产av中文字幕| 亚洲欧洲黄色网| 欧美一区二区三区粗大| 久久久久久久久久久妇女| 欧美成年人视频网站| 在线观看成人毛片| 日韩天堂av| 国产成人一区二区三区小说| 中文字幕一区二区人妻痴汉电车| 精品一区二区三区在线观看| 国产成人免费电影| 免费在线黄色网址| 中文字幕在线一区免费| 乱子伦一区二区| 黄毛片在线观看| 欧美性受xxxx| 亚洲AV成人精品| 欧美人与动xxxxz0oz| 亚洲图片在线综合| 1024手机在线视频| 先锋影音久久久| 91精品国产自产在线老师啪| 后进极品白嫩翘臀在线视频| 久久久久久9999| 欧美三级午夜理伦三级老人| 嗯啊主人调教在线播放视频 | 国产午夜精品一区二区三区嫩草| 亚洲欧洲一区二区| 丁香花在线高清完整版视频| 色av成人天堂桃色av| 91视频免费入口| 综合色就爱涩涩涩综合婷婷| www.日韩av.com| 国产成人无码精品久在线观看| 秋霞午夜鲁丝一区二区老狼| av免费精品一区二区三区| 欧美xxx.com| 一区二区三区免费| 91精品无人成人www| 欧美电影在线观看完整版| 久久精品中文字幕| 高清乱码免费看污| 成人免费观看男女羞羞视频| 亚洲欧美日韩另类精品一区二区三区 | 亚洲天天在线日亚洲洲精| 色在线观看视频| 蜜桃av一区二区| 明星裸体视频一区二区| 国产欧美黑人| 欧美视频中文字幕| 特级西西人体4444xxxx| 欧美.日韩.国产.一区.二区| 国产精品久久久久久久久久久久久久 | 一区二区三区欧美在线| 免费成人美女女| 亚洲成人精品久久| 欧美日韩在线视频免费播放| 奇米影视一区二区三区小说| 久久riav二区三区| 波多野结衣中文字幕久久| 欧美久久久久久久久中文字幕| 欧美福利第一页| 亚洲免费在线| 美女一区视频| bl在线肉h视频大尺度| 欧美一区二区三区系列电影| 国产jizz18女人高潮| 日韩和欧美一区二区三区| 狼狼综合久久久久综合网| av中文在线资源| 91精品国产乱码久久蜜臀| 熟女av一区二区| 奇米精品一区二区三区四区| 日韩欧美亚洲日产国产| 日韩不卡免费高清视频| 日韩av综合中文字幕| 国产精品久免费的黄网站| 99久久综合精品| 国产免费观看高清视频| 国产一区调教| 国产91精品高潮白浆喷水| 丰满肉肉bbwwbbww| 天天操天天干天天综合网| 亚洲国产第一区| 日韩一级精品| 蜜桃成人免费视频| 一二区成人影院电影网| 在线观看免费高清视频97| 中文在线观看免费高清| 国产精品毛片a∨一区二区三区| 香港日本韩国三级网站| 欧美成人milf| 5566av亚洲| a国产在线视频| 亚洲精品一区久久久久久| 波多野结衣啪啪| 国产精品全国免费观看高清| 亚洲制服中文字幕| 亚洲欧美一区在线| 国产欧美一区二区三区另类精品| 91av久久| 亚洲天堂男人天堂| 91在线公开视频| 一区二区三区四区蜜桃| 在线免费播放av| 日韩va欧美va亚洲va久久| 亚洲一区三区| 成午夜精品一区二区三区软件| 欧亚精品中文字幕| 精精国产xxxx视频在线| 欧美大片在线观看| 永久免费无码av网站在线观看| 国产精品你懂的| 欧洲成人午夜精品无码区久久| 一本色道久久| 国产高清精品软男同| 9l视频自拍蝌蚪9l视频成人| 欧美在线免费观看| 超碰在线无需免费| 日韩大片在线观看视频| 伊人成人在线观看| 亚洲成人在线网站| 免费一级suv好看的国产网站| 国产成a人亚洲精品| 国产又大又硬又粗| 欧美搞黄网站| 日韩黄色影视| 大桥未久女教师av一区二区| 国产精品日韩电影| 欧美在线极品| 欧美成人免费一级人片100| 色在线免费视频| 日韩午夜在线影院| 中日精品一色哟哟| 精品福利在线视频| 极品魔鬼身材女神啪啪精品| 久久久久国产成人精品亚洲午夜| 无人码人妻一区二区三区免费| 久久午夜影视| 日韩 欧美 视频| 亚洲高清影视| 日韩欧美国产二区| 日本成人7777| 超碰97国产在线| 亚洲高清影院| 国产精品久久999| 国产精品25p| 久久99久久99精品免观看粉嫩| aaa在线观看| 精品亚洲一区二区三区四区五区| 性猛交富婆╳xxx乱大交天津| 欧美性猛交一区二区三区精品| 日韩精品视频播放| 亚洲综合在线第一页| 男的操女的网站| 国产精品久久久久aaaa樱花| 好吊视频在线观看| 久久天堂av综合合色蜜桃网| 香蕉视频污视频| 国产精品66部| 日本成人在线免费| 国产精一品亚洲二区在线视频| 91欧美视频在线| 蜜桃一区二区三区四区| 国产xxxxx视频| 视频一区在线播放| 麻豆av免费在线| 丝瓜av网站精品一区二区| 久久婷婷五月综合色国产香蕉| 亚洲高清成人| 成人精品视频在线播放| 在线成人av| 欧美深夜福利视频| 夜夜夜久久久| 免费在线观看毛片网站| 免费一级欧美片在线播放| 久久久999视频| 午夜一区在线| 噼里啪啦国语在线观看免费版高清版 | 久热在线中文字幕色999舞| 免费在线观看黄| 久久精品视频导航| 午夜小视频福利在线观看| 九九九久久久久久| 高清电影在线免费观看| 高清欧美性猛交xxxx黑人猛交| 国产乱码在线| 777精品视频| 欧美一区 二区 三区| 国产精品美乳在线观看| 中文字幕日本一区| 97超级在线观看免费高清完整版电视剧| 不卡一区视频| 成人区精品一区二区| 日韩免费电影在线观看| 欧美一区二区综合| 91麻豆国产自产在线观看亚洲 | 一本久道久久综合狠狠爱| 国产91在线视频观看| 日韩成人精品视频| 亚洲一级片免费观看| 不卡高清视频专区| 精品欧美一区二区久久久| 国产精品久久国产精麻豆99网站| 欧美日韩中文字幕在线观看| 亚洲1区2区3区4区| 中文字幕免费高清在线观看| 欧美一区二区性放荡片| 男人天堂综合网| 一本色道久久88综合日韩精品| 国产在线观看免费麻豆| 国内精品模特av私拍在线观看| 日韩电影免费观看高清完整版| 国产在线精品一区免费香蕉| 97久久综合区小说区图片区| 欧美乱偷一区二区三区在线| 99精品视频精品精品视频 | 日韩成人精品视频| 精品国产一二区| 国产女人18水真多18精品一级做| 激情综合网五月天| 色婷婷久久综合| av中文字幕第一页| 亚洲欧美激情视频| 色综合999| 国产精品精品视频一区二区三区| 婷婷综合国产| 亚洲春色在线| 亚洲最黄网站| 特级黄色片视频| 久久免费午夜影院| 激情小说中文字幕| 欧美性极品少妇| 亚洲欧美自偷自拍| 欧美成人在线网站| 美女色狠狠久久| 久久久久久一区| 国内成人在线| 污视频网址在线观看| 久久婷婷色综合| 激情四射综合网| 欧美日韩精品高清| 免费成人av电影| 97免费中文视频在线观看| 国产视频一区二区在线播放| 四虎一区二区| 亚洲综合三区| 国产乱了高清露脸对白| 亚洲综合免费观看高清完整版| 一级α片免费看刺激高潮视频| 国产丝袜精品视频| gratisvideos另类灌满| av成人综合网| 综合精品一区| 一本一道久久a久久综合蜜桃| 国产亚洲一本大道中文在线| 日韩精品一区二区三| 欧美va天堂va视频va在线| 黄色在线观看网站| 国产精品影片在线观看| 国内精品伊人久久久| 日韩网址在线观看| 99re6这里只有精品视频在线观看| 久久久久亚洲av片无码下载蜜桃| 欧美一区二区福利视频| 麻豆网在线观看| 国产精自产拍久久久久久| 国产伦一区二区三区| 日本精品一区二区三区四区| 91免费版在线| 二区视频在线观看| 精品亚洲国产视频| 夜鲁夜鲁夜鲁视频在线播放| 精品欧美一区二区精品久久| 日韩视频二区| 无码熟妇人妻av| 欧美性猛交xxxx乱大交极品| 天天操天天干天天干| 2019中文字幕在线免费观看| 欧美精品中文字幕亚洲专区| 中文字幕无码精品亚洲35| 菠萝蜜视频在线观看一区| 亚洲综合一二三| 精品小视频在线| 国产成人免费9x9x人网站视频| 日本一区视频在线观看| 日本午夜一区二区| 亚洲熟女毛茸茸| 日韩欧美高清dvd碟片| 国产区美女在线| 久久久免费看| 麻豆极品一区二区三区| 国产老头老太做爰视频| 日韩欧美在线综合网| av电影在线地址| 欧美亚洲精品日韩| 美日韩一级片在线观看| 久久久久99精品成人片试看| 亚洲电影免费观看| 小h片在线观看| 亚洲图片都市激情| 国产成a人无v码亚洲福利| 日韩精品久久久久久久| 国产亚洲精品久久| 国产一区二区三区| 日韩a∨精品日韩在线观看| 日本一区二区综合亚洲| 国产极品999| 欧美一区二区三区免费观看| 日韩大片在线| 国产精品99精品无码视亚| 日本精品免费观看高清观看| 黄色网址在线免费| 精品国产一区二区三区麻豆免费观看完整版 | 欧美日本亚洲视频| 色综合久久中文| 欧美成人乱码一二三四区免费| 亚洲国产中文字幕在线视频综合| 你懂的免费在线观看| 亚洲自拍偷拍网址| 亚洲一区二区三区高清不卡| 国产精品久久国产精麻豆96堂| 亚洲精品在线网站| 久久69成人| 国产欧美日韩网站| 亚洲欧洲精品一区二区三区| 午夜一区在线观看| 91最新国产视频| 老司机午夜精品视频在线观看| 美国黄色小视频|