더보기
같이 한 번 알아봅시다~
Activity.java
...
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
...
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
if (TextUtils.equals(getPackageName(),
intent.resolveActivity(getPackageManager()).getPackageName())) {
// Apply Autofill restore mechanism on the started activity by startActivity()
final IBinder token =
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
// Remove restore ability from current activity
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
// Put restore token
intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
}
}
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
...
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
Activity 내에서 startActivity를 호출해주게 될 경우, 프레임워크 단의
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
메서드가 불리게 된다
결국 해당 메서드를 확인해보면 mInstrumentation.execStartActivity 부분이 호출되게 된다
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this, // 혹은 child
intent, requestCode, options);
instrumentation.java
@UnsupportedAppUsage
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
ActivityTaskManagerService의 startActivity를 호출 해 준다
ActivityTaskManagerService.java
...
ActivityStartController getActivityStartController() {
return mActivityStartController;
}
...
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
...
@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
...
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();
}
ActivityTaskManagerService의 startActivityAsUser에서는
Builder patter 형식으로 ActivityStartController를 통해 ontainStarter를 해주고
ActivityStarter의 execute 메서드를 호출 시킨다
ActivityStartController.java
...
private final Factory mFactory;
...
ActivityStartController(ActivityTaskManagerService service) {
this(service, service.mTaskSupervisor,
new DefaultFactory(service, service.mTaskSupervisor,
new ActivityStartInterceptor(service, service.mTaskSupervisor)));
}
...
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
ActivityStartController는 생성시에 ActivityStarter에서 static으로 선언되어 있는 DefaultFactory를 생성한다
그리고, ActivityTaskManager의 startActivityAsUser에서 ActivityStarter의 execute를 호출해준다
ActivityStarter.java (Factory)
@VisibleForTesting
interface Factory {
/**
* Sets the {@link ActivityStartController} to be passed to {@link ActivityStarter}.
*/
void setController(ActivityStartController controller);
/**
* Generates an {@link ActivityStarter} that is ready to handle a new start request.
* @param controller The {@link ActivityStartController} which the starter who will own
* this instance.
* @return an {@link ActivityStarter}
*/
ActivityStarter obtain();
/**
* Recycles a starter for reuse.
*/
void recycle(ActivityStarter starter);
}
...
/**
* Default implementation of {@link StarterFactory}.
*/
static class DefaultFactory implements Factory {
...
DefaultFactory(ActivityTaskManagerService service,
ActivityTaskSupervisor supervisor, ActivityStartInterceptor interceptor) {
mService = service;
mSupervisor = supervisor;
mInterceptor = interceptor;
}
...
@Override
public ActivityStarter obtain() {
ActivityStarter starter = mStarterPool.acquire();
if (starter == null) {
if (mService.mRootWindowContainer == null) {
throw new IllegalStateException("Too early to start activity.");
}
starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
}
return starter;
}
...
ActivityStarter.java (execute)
/**
* Resolve necessary information according the request parameters provided earlier, and execute
* the request which begin the journey of starting an activity.
* @return The starter result.
*/
int execute() {
try {
// Refuse possible leaked file descriptors
if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
...
int res;
synchronized (mService.mGlobalLock) {
final boolean globalConfigWillChange = mRequest.globalConfig != null
&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (rootTask != null) {
rootTask.mConfigWillChange = globalConfigWillChange;
}
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
+ "will change = %b", globalConfigWillChange);
final long origId = Binder.clearCallingIdentity();
res = resolveToHeavyWeightSwitcherIfNeeded();
if (res != START_SUCCESS) {
return res;
}
res = executeRequest(mRequest); // 여기
...
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
newActivityCreated, mLastStartActivityRecord, originalOptions);
if (mRequest.waitResult != null) {
mRequest.waitResult.result = res;
res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
launchingState);
}
return getExternalResult(res);
}
} finally {
onExecutionComplete();
}
ActivityStarter의 execute 에서 중요한 것은 executeRequest를 호출 해주는 부분입니다
ActivityStarter.java (executeRequest)
private int executeRequest(Request request) {
if (TextUtils.isEmpty(request.reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
}
...
WindowProcessController homeProcess = mService.mHomeProcess;
boolean isHomeProcess = homeProcess != null
&& aInfo.applicationInfo.uid == homeProcess.mUid;
if (!restrictedBgActivity && !isHomeProcess) {
mService.resumeAppSwitches();
}
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
inTask, inTaskFragment, restrictedBgActivity, intentGrants);
if (request.outActivity != null) {
request.outActivity[0] = mLastStartActivityRecord;
}
return mLastStartActivityResult;
}
executeRequest 메서드 안도 매우 복잡하지만 startActivity가 이루어지는 부분을 보려면
startActivityUnchecked 부분만 보면 됩니다
이후 부분은 2번째 블로그에서 다시 작성하도록 하겠습니다
'안드로이드 > 안드로이드 프레임워크' 카테고리의 다른 글
Android framework StartActivity 호출 순서 (0) | 2022.05.09 |
---|---|
StartActivity 호출 시 코드 진행 순서 3 (0) | 2022.04.30 |
StartActivity 호출 시 코드 진행 순서 2 (0) | 2022.04.29 |
Dagger (0) | 2022.04.13 |
안드로이드 4대 컴포넌트 (0) | 2022.04.10 |