Activity Record、Activity ClientRecord、Activityの関係


Activity起動プロセスのソースコードを読むときにActivity RecordとActivity ClientRecordに遭遇しましたが、これら2つはActivityとどのような関係がありますか?

結論


 Activity Record、Activity ClientRecord、Activity、Activityの3つが1つずつ対応しています.

ぶんせき


Activity Recordはシステム_Serverプロセスのオブジェクト、Activity ClientRecord、ActivityはAppプロセスのオブジェクトですが、3つの間にどのように対応関係があるのでしょうか.次に私が分析します.

ActivityRecord


Activity起動プロセスでシステム_Serverプロセスでは、次の方法でチェーンが呼び出されます.
ActivityManagerService.startActivity() 
ActvityiManagerService.startActivityAsUser() 
ActivityStackSupervisor.startActivityMayWait() 
ActivityStackSupervisor.startActivityLocked() 

私たちはActivity StackSupervisorで発見することができます.startActivity Locked()にActivity Recordが作成されています.
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 weakActivity;
        private final ActivityManagerService mService;

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

以上のコードから、Activity Recordにはメンバー変数appTokenがあり、タイプはTokenであり、IApplicationTokenを継承していることがわかる.Stub.明らかに、appTokenはプロセス間で転送できます(IApplicationToken.StubはBinderを継承しているので、appToken自体がBinderオブジェクトですか).さらにTokenにはActivity Recordの弱い参照があり,つまりappTokenでActivity Recordを見つけることができる.ここまで言うと、すぐに考えがあるのではないでしょうか.AppTokenをAppプロセスに転送し、Activity ClientRecordとActivityに値を割り当てるだけで、3つの対応関係が成り立つのではないでしょうか.ソースコードでも確かにそうしています.次に、この新しいActivityを起動するためにActivity StackSupervisorが呼び出されます.realStartActivity Locked()メソッド.
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 pendingResults, List 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


システムでサーバプロセスの呼び出しActivity StackSupervisor.realStartActivity Locked()の後、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 pendingResults, List 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()メソッドでActivity ClientRecordが作成され、そのActivity ClientRecordにtokenが割り当てられます.その後、Activity ClientRecordは、プライマリスレッドActivity Thread処理に送信される.次の方法でチェーンを呼び出します.
ActivityThread.sendMessage() 
ActivityThread.H.sendMessage() 
ActivityThread.H.handleMessage() 
ActivityThread.handleLauncherActivity() 
ActivityThread.performLauncherActivity()
public final class ActivityThread {
	……
	final ArrayMap 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);
		……
	}	

}

見られる.performLauncherActivity()メソッドでActivityが作成され、Activityが呼び出されます.attach().Activity.attach()メソッドにActivity ClientRecordが入力されました.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()でActivity ClientRecord.tokenはActivityに割り当てられたmToken.これで,Activity Record,Activity ClientRecord,Activityの3つの対応関係が確立される.

Tokenの利用


以上、Activity Record、Activity ClientRecord、Activityの3つがどのように対応関係を確立しているのかを分析しましたが、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;
    }
    ...
}

  上のコード注記で、現在フォーカスを取得しているActivity Recordの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(Activity ClientRecord,Intent customIntent)が呼び出され、最後にtokenをKey、Activity ClientRecordをvalueとしてActivity ClientRecordが保存されます.次にperformPauseActivity()に移動すると、対応するActivity ClientRecordがtokenに従って取り出されます.Activity ClientRecordに保存されている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);
	……
}

次にActivity Stackに呼び出す.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の弱い参照に基づいて対応するActivity Recordが見つかります.最後に、見つかったActivity Recordが保存したmPausingActivityと同じオブジェクトであるかどうかを判断します.もしそうであれば、completePauseLocked(true)が実行され、AMSがActivity呼び出しonPause()のメッセージを受信したことを示す.

最後に


Activity情報を保存するオブジェクトは、ActivityレコードとActivity ClientRecordです.ただし、Activity Recordはシステムに帰属します.サーバプロセスで使用され、Activity ClientRecordはAppプロセスで使用されます.

参考記事:


4つのコンポーネントのActivity Record