ActivityRecord、ActivityClientRecord、Activity的關係

  在閱讀Activity啓動流程的源碼時遇到了ActivityRecord和ActivityClientRecord,那麼它們兩個和Activity有什麼關係呢?

結論

  ActivityRecord、ActivityClientRecord、Activity,三者一一對應。

分析

  ActivityRecord是system_server進程中的對象,ActivityClientRecord和Activity都是App進程中的對象,那麼三者之間是如何建立起一一對應的關係呢?下面我來分析下。

ActivityRecord

  在Activity啓動流程中system_server進程會經歷以下方法調用鏈:

ActivityManagerService.startActivity() 
ActvityiManagerService.startActivityAsUser() 
ActivityStackSupervisor.startActivityMayWait() 
ActivityStackSupervisor.startActivityLocked() 

  我們可以發現在ActivityStackSupervisor.startActivityLocked() 中創建了ActivityRecord。

final int startActivityLocked(IApplicationThread caller,
        Intent intent, String resolvedType, ActivityInfo aInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode,
        int callingPid, int callingUid, String callingPackage,
        int realCallingPid, int realCallingUid, int startFlags, Bundle options,
        boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
        ActivityContainer container, TaskRecord inTask) {
   		 int err = ActivityManager.START_SUCCESS;

  		  ...
		
		ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
            requestCode, componentSpecified, voiceSession != null, this, container, options);

		  ...

 	   err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
            startFlags, true, options, inTask);

        ...
        return err;
}
final class ActivityRecord {
	final IApplicationToken.Stub appToken; // window manager token

	ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
            int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
            ActivityInfo aInfo, Configuration _configuration,
            ActivityRecord _resultTo, String _resultWho, int _reqCode,
            boolean _componentSpecified, boolean _rootVoiceInteraction,
            ActivityStackSupervisor supervisor,
            ActivityContainer container, Bundle options) {
			……
			appToken = new Token(this, service);
			……
	}

	static class Token extends IApplicationToken.Stub {
		private final WeakReference<ActivityRecord> weakActivity;
        private final ActivityManagerService mService;

        Token(ActivityRecord activity, ActivityManagerService service) {
            weakActivity = new WeakReference<>(activity);
            mService = service;
        }
	}
}

  從上面代碼中可以看出ActivityRecord有一個成員變量appToken,類型爲Token,繼承了IApplicationToken.Stub。很明顯,appToken可以跨進程傳輸(因爲IApplicationToken.Stub繼承了Binder,appToken本身就是個Binder對象嘛)。而且Token中還持有ActivityRecord的弱引用,也就是說可以通過appToken找到ActivityRecord.
  講到這裏,是不是馬上就有思路了。只要把appToken傳到App進程中,並賦值給ActivityClientRecord和Activity,那麼三者的一一對應關係不就建立來了嗎。
  源碼中也的確是這麼做的。
  接下來,爲了啓動這個新的Activity,就會調用ActivityStackSupervisor.realStartActivityLocked()方法。

final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {
`		……
		app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
		……

}

  app.thread其實就是IApplicationThread對象,實際類型是ApplicationThreadProxy。這裏又是Binder通信。

final class ProcessRecord {
	IApplicationThread thread; 
}

public interface IApplicationThread extends IInterface {
	……
	void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
            CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
            int procState, Bundle state, PersistableBundle persistentState,
            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException;
     ……
}

public abstract class ApplicationThreadNative extends Binder
        implements IApplicationThread {
       ……
}

//system_server進程持有ApplicationThreadProxy
class ApplicationThreadProxy implements IApplicationThread {
		……
}

//App進程持有ApplicationThread
private class ApplicationThread extends ApplicationThreadNative {
	……
}

  調用scheduleLaunchActivity()方法將appToken傳遞給App進程。

ActivityClientRecord

  在system_server進程中的調用ActivityStackSupervisor.realStartActivityLocked()後,Android系統會在App進程中調用ApplicationThread.scheduleLaunchActivity()方法。

private class ApplicationThread extends ApplicationThreadNative {
	@Override
     public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
			……
			ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            ……
            //調用ActivityThread.sendMessage()
            sendMessage(H.LAUNCH_ACTIVITY, r);
	}

}

  可以看到ApplicationThread.scheduleLaunchActivity()方法中創建了ActivityClientRecord,並將token賦值給了該ActivityClientRecord。然後又將ActivityClientRecord發送給主線程ActivityThread處理。經歷了以下方法調用鏈。

ActivityThread.sendMessage() 
ActivityThread.H.sendMessage() 
ActivityThread.H.handleMessage() 
ActivityThread.handleLauncherActivity() 
ActivityThread.performLauncherActivity()
public final class ActivityThread {
	……
	final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
	……
	private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
		……
		Activity activity = null;
    	try {
    		java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
	    	activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
         	……
    	 } catch (Exception e) {
          	 ……
    	 }

		try {
			……
			activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor);
			……
		}……
		……
		//以ActivityClientRecord.token爲Key保存了ActivityClientRecord
		mActivities.put(r.token, r);
		……
	}	

}

  可以看到ActivityThread.performLauncherActivity()方法中創建了Activity,並調用了Activity.attach()。在Activity.attach()方法中傳入了ActivityClientRecord.token。

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {
	……
	private IBinder mToken;
	……
	final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
		……
		mToken = token;
		……
	}
}

  然後在Activity.attach()中將ActivityClientRecord.token賦值給了Activity.mToken。至此,ActivityRecord、ActivityClientRecord、Activity三者的一一對應關係就建立完畢了。

Token的利用

  上文已經分析完ActivityRecord、ActivityClientRecord、Activity三者如何建立對應關係的了,那麼Android系統又是如何利用這層對應關係的呢。熟悉Activity啓動流程的同學都知道Activity的生命週期實際上是由AMS控制的,比如啓動Activity時需要令上一個Activity執行onPause()方法。這時會經歷以下方法調用鏈。

ActivityStack.startPausingLocked() 
IApplicationThread.schudulePauseActivity() 
ActivityThread.sendMessage() 
ActivityThread.H.sendMessage(); 
ActivityThread.H.handleMessage() 
ActivityThread.handlePauseActivity() 
ActivityThread.performPauseActivity() 
Activity.performPause() 
Activity.onPause() 
ActivityManagerNative.getDefault().activityPaused(token) 
ActivityManagerService.activityPaused() 
ActivityStack.activityPausedLocked() 
ActivityStack.completePauseLocked()
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
        boolean dontWait) {
    ...
    if (prev.app != null && prev.app.thread != null) {
        ……
        try {
            ……
            //prev就是當前獲得焦點的ActivityRecord,現在的目的是令該ActivityRecord對應的Activity調用onPause()
            prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                    userLeaving, prev.configChangeFlags, dontWait);
        } catch (Exception e) {
            ……
            mPausingActivity = null;
            mLastPausedActivity = null;
            mLastNoHistoryActivity = null;
        }
    } else {
        mPausingActivity = null;
        mLastPausedActivity = null;
        mLastNoHistoryActivity = null;
    }
    ...
}

  上面代碼註釋處,將當前獲得焦點的ActivityRecord的appToken發給App進程。接下來調用ActivityThread.performPauseActivity()

final Bundle performPauseActivity(IBinder token, boolean finished,
            boolean saveState) {
        ActivityClientRecord r = mActivities.get(token);
        return r != null ? performPauseActivity(r, finished, saveState) : null;
}

final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
            boolean saveState) {
	……
	mInstrumentation.callActivityOnPause(r.activity);
	……
}

public class Instrumentation {
	public void callActivityOnPause(Activity activity) {
        activity.performPause();
    }
}

  之前啓動Activity時會調用performLaunchActivity(ActivityClientRecord r, Intent customIntent),並在最後以token爲Key,ActivityClientRecord爲value保存ActivityClientRecord。然後到了performPauseActivity()中又會根據token取出對應ActivityClientRecord。再調用ActivityClientRecord中保存的activity的onPause()方法。

performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
	……
	mActivities.put(r.token, r);
	……
}

  執行完performPauseActivity()方法後,還要告知AMS,onPause()方法調用完畢。將token傳回AMS。

private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
	……
	performPauseActivity(token, finished, r.isPreHoneycomb());
	……
	ActivityManagerNative.getDefault().activityPaused(token);
	……
}

  接着調用到ActivityStack.activityPausedLocked() 。

final class ActivityStack {
	final void activityPausedLocked(IBinder token, boolean timeout) {
       ……
        final ActivityRecord r = isInStackLocked(token);
        if (r != null) {
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            if (mPausingActivity == r) {
                completePauseLocked(true);
            } else {
                ……
            }
        }
    }

	ActivityRecord isInStackLocked(IBinder token) {
        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
        return isInStackLocked(r);
    }
}

final class ActivityRecord {
	static ActivityRecord forTokenLocked(IBinder token) {
        try {
            return Token.tokenToActivityRecordLocked((Token)token);
        } catch (ClassCastException e) {
            Slog.w(TAG, "Bad activity token: " + token, e);
            return null;
        }
    }

	static class Token extends IApplicationToken.Stub {
	
		private static final ActivityRecord tokenToActivityRecordLocked(Token token) {
            if (token == null) {
                return null;
            }
            ActivityRecord r = token.weakActivity.get();
            if (r == null || r.task == null || r.task.stack == null) {
                return null;
            }
            return r;
        }
    }
}

  AMS收到token後,根據token中的弱引用找到了對應的ActivityRecord。最後判斷找到的ActivityRecord是否與保存的mPausingActivity是同一個對象。若是,就執行completePauseLocked(true),說明AMS已經收到Activity已調用onPause()的消息。

最後

  ActivityRecord和ActivityClientRecord都是保存Activity信息的對象。只不過,ActivityRecord歸system_server進程使用,ActivityClientRecord歸App進程使用。

參考文章:

四大組件之ActivityRecord

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章