Android Activity 의 시작 프로 세 스 를 자세히 알 아 보기

머리말
activity 가 시작 하 는 절 차 는 두 부분 으로 나 뉜 다.하 나 는 activity 에서 startActivity(Intent intent)방법 으로 Activity 를 시작 하 는 것 이다.둘째,데스크 톱 에서 아이콘 을 누 르 면 App 을 시작 하고 Activity 를 표시 합 니 다.두 번 째 방식 은 첫 번 째 방식 에 비해 더욱 전면적 이기 때문에 본 고 는 두 번 째 절차 로 분석 할 것 이다.
간명 하 다
우리 핸드폰 의 데스크 톱 은 Launcher 라 는 Activity 로 핸드폰 에 있 는 응용 아이콘 을 나열 하고 아이콘 에는 apk 를 설치 할 때 분석 하 는 응용 기본 시작 페이지 등 정보 가 포함 되 어 있 습 니 다.아이콘 을 눌 렀 을 때 시작 할 App 과 Launcher,AMS,Zygote 소속 프로 세 스 가 다 르 기 때문에 Launcher 와 AMS,AMS 와 Zygote,AMS 와 새 App 등 네 가지 가 여러 번 통신 해 야 하나의 App 을 시작 할 수 있 습 니 다.그리고 Activity 를 시작 합 니 다.전체적인 순서 도 는 다음 과 같 습 니 다.

다음은 소스 코드 에 따라 절 차 를 정리 하 겠 습 니 다.
1.Launcher 가 AMS 에 시작 Activity 보 내기
Launcher 자 체 는 Activity 입 니 다.사용자 가 아이콘 을 클릭 할 때 startActivity Safely 방법 을 호출 하고 마지막 으로 Activity.startActivity()로 호출 합 니 다.함 수 는 다음 과 같 습 니 다.

Launcher.java
 public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
  ...
  //        
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  ...
  startActivity(intent, optsBundle);
  ...
 }

Activity.java
 @Override
 public void startActivity(Intent intent) {
  this.startActivity(intent, null);
 }

 @Override
 public void startActivity(Intent intent, @Nullable Bundle options) {
  ...
  if (options != null) {
   //-1 requestCode             
   startActivityForResult(intent, -1, options);
  } else {
   startActivityForResult(intent, -1);
  }
 }

 public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
   @Nullable Bundle options) {
   ...
   Instrumentation.ActivityResult ar =
    mInstrumentation.execStartActivity(
     this, mMainThread.getApplicationThread(), mToken,this,intent, requestCode, options);
   ...
 }
모든 Activity 는 Instrumentation 대상 을 가지 고 있 습 니 다.exec Start Activity 함 수 를 통 해 Activity 를 시작 하 는 절 차 를 계속 수행 합 니 다.이 함수 에는 mMainThread.getApplicationThread()가 들 어 왔 습 니 다.Activity Thread 의 내부 클래스 ApplicationThread 를 얻 었 습 니 다.이것 은 Binder 대상 이 고 그 후에 AMS 는 이 대상 을 통 해 App 과 통신 합 니 다.

Instrumentation.java
public ActivityResult execStartActivity(
   Context who, IBinder contextThread, IBinder token, Activity target,
   Intent intent, int requestCode, Bundle options) {
 ...
	int result = ActivityTaskManager.getService().startActivity(whoThread,who.getBasePackageName(),
  who.getAttributionTag(),intent,intent.resolveTypeIfNeeded(who.getContentResolver()),
  token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); 
 ...
}

ActivityTaskManager.java
public static IActivityTaskManager getService() {
  return IActivityTaskManagerSingleton.get();
}
 
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
   new Singleton<IActivityTaskManager>() {
    @Override
    protected IActivityTaskManager create() {
     final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
     return IActivityTaskManager.Stub.asInterface(b);
    }
    }
};
이 단 계 는 Launcher 가 AMS 에 통신 하기 시 작 했 습 니 다.서로 다른 프로 세 스 때문에 Binder 를 통 해 통신 해 야 합 니 다.IActivity Task Manager 는 AMS 엔 드 Binder 를 대리 하 는 대상 이 고 그 후에 AMS 는 startActivity 를 시작 합 니 다.여기 서 Launcher 가 AMS 에 Activity 를 시작 하 라 고 요청 하면 프로 세 스 가 끝 납 니 다.
2.AMS 가 Activity 를 시작 하고 Launcher 에 Paused 상태 로 들 어 오 라 고 알 립 니 다.
현재 프로 세 스 는 AMS,즉 다른 프로 세 스 입 니 다.이전 단 계 는 대 리 를 통 해 AMS 의 startActivity 방법 으로 호출 되 었 습 니 다.다음 호출 은 다음 과 같 습 니 다.

ActivityTaskManagerService.java
 @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) {
	 ...
  userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
    Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
    
  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();
 }
 
 ActivityStarter obtainStarter(Intent intent, String reason) {
  return mFactory.obtain().setIntent(intent).setReason(reason);
 }
위의 몇 단 계 는 주로 권한 검 사 를 하 는 것 이다.

ActivityStarter.java
 int execute() {
 ...
 res = executeRequest(mRequest);
 ...
 }
//            
ActivityStack.java
 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
 ...
 if (mResumedActivity != null) {
  pausing |= startPausingLocked(userLeaving, false , next);
 }
 ...
 mStackSupervisor.startSpecificActivity(next, true, false);
 ...
 }
startPausing Locked 방법 은 주로 Launcher 에 Paused 상태 로 들 어가 라 고 알 리 는 것 입 니 다.이 상태 에 들 어간 후에 Activity Stack Supervisor.startSpecific Activity 방법 으로 새로운 App 프로 세 스 상 태 를 판단 하여 서로 다른 응답 을 합 니 다.다음 과 같 습 니 다.

ActivityStackSupervisor.java
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
  //       Activity    
  final WindowProcessController wpc =
    mService.getProcessController(r.processName, r.info.applicationInfo.uid);
  boolean knownToBeDead = false;
  //                           Activity(  Activity     )
  if (wpc != null && wpc.hasThread()) {
   try {
    realStartActivityLocked(r, wpc, andResume, checkConfig);
    return;
   } catch (RemoteException e) {
    Slog.w(TAG, "Exception when starting activity "
      + r.intent.getComponent().flattenToShortString(), e);
   }

   // If a dead object exception was thrown -- fall through to
   // restart the application.
   knownToBeDead = true;
  }
	//    AMS Zygote          
  r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
  final boolean isTop = andResume && r.isTopRunningActivity();
  mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
지금까지 Launcher 와 AMS 의 통신,그리고 AMS 와 Zygote 프로 세 스 의 통신 이 완료 되 었 습 니 다.다음은 시작 할 App 의 스 레 드,즉 Activity Thread 를 만 들 것 입 니 다.
3.새로운 프로 세 스 시작,Activity Thread 의 main 함수 입구
이전 Zygote 에서 새 프로 세 스 를 시작 할 때 Activity Thread.main 함 수 를 표시 합 니 다.Zygote 에서 새 프로 세 스 를 만 든 후 이 방법 을 반사 적 으로 호출 합 니 다.현재 새 App 프로 세 스 에 있 습 니 다.

ActivityThread.java
 public static void main(String[] args) {
  ...
  Looper.prepareMainLooper();
	...
  ActivityThread thread = new ActivityThread();
  thread.attach(false, startSeq);
	...
  Looper.loop();
	...
 }
 
 private void attach(boolean system, long startSeq) {
   final IActivityManager mgr = ActivityManager.getService();
   try {
    mgr.attachApplication(mAppThread, startSeq);
   } catch (RemoteException ex) {
    throw ex.rethrowFromSystemServer();
   }
   ...
 }
ActivityManagerService.java
 private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
   int pid, int callingUid, long startSeq) {
   ...
   thread.bindApplication(processName, appInfo, providerList,
      instr2.mClass,
      profilerInfo, instr2.mArguments,
      instr2.mWatcher,
      instr2.mUiAutomationConnection, testMode,
      mBinderTransactionTrackingEnabled, enableTrackAllocation,
      isRestrictedBackupMode || !normalMode, app.isPersistent(),
      new Configuration(app.getWindowProcessController().getConfiguration()),
      app.compat, getCommonServicesLocked(app.isolated),
      mCoreSettingsObserver.getCoreSettingsLocked(),
      buildSerial, autofillOptions, contentCaptureOptions,
      app.mDisabledCompatChanges);
    ...
    didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
    ...
 }
여 기 는 주로 Looper 와 Activity Thread 대상 을 만 든 다음 에 현재 응용 프로그램 Thread 를 AMS 에 등록 합 니 다.응용 프로그램 Thread 는 Activity Thread 의 내부 클래스 로 IApplicationThread.Stub 를 실 현 했 습 니 다.이 대상 으로 프로 세 스 를 뛰 어 넘 을 수 있 습 니 다.위의 코드 논 리 는 두 단계 로 나 뉘 는데 첫 번 째 단 계 는 AMS 가 응용 프로그램 Thread 를 연결 할 때 H.BIND 를 보 냈 습 니 다.APPLICATION 의 Message 는 Handler 에서 이 메 시 지 를 처리 할 때 Application 의 onCreate 방법 을 호출 했 습 니 다.두 번 째 단 계 는 mAtm Internal 의 attachApplication 에서 Activity Stack Supervisor.realStart Activity Locked 방법 으로 층 층 이 호출 되 었 습 니 다.전체적으로 다음 과 같 습 니 다.

public final void bindApplication(String processName, ApplicationInfo appInfo,
    ProviderInfoList providerList, ComponentName instrumentationName,
    ProfilerInfo profilerInfo, Bundle instrumentationArgs,
    IInstrumentationWatcher instrumentationWatcher,
    IUiAutomationConnection instrumentationUiConnection, int debugMode,
    boolean enableBinderTracking, boolean trackAllocation,
    boolean isRestrictedBackupMode, boolean persistent, Configuration config,
    CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
    String buildSerial, AutofillOptions autofillOptions,
    ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
    	...
    	sendMessage(H.BIND_APPLICATION, data);
 }
    
public void handleMessage(Message msg) {
 switch (msg.what) {
  case BIND_APPLICATION:
  	AppBindData data = (AppBindData)msg.obj;
  	handleBindApplication(data);
  	Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
  	break;
  ...
  }
}

private void handleBindApplication(AppBindData data) {
	...
	mInstrumentation.callApplicationOnCreate(app);
	...
}
지금까지 새로운 앱 스 레 드 가 시작 되 고 애플 리 케 이 션 에 연결 되 어 있 습 니 다.
4.액 티 비 티 만 들 기

ActivityStackSupervisor.java
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
  boolean andResume, boolean checkConfig) throws RemoteException {
  ...
  final ClientTransaction clientTransaction = ClientTransaction.obtain(
    proc.getThread(), r.appToken);
   final DisplayContent dc = r.getDisplay().mDisplayContent;
   clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
     System.identityHashCode(r), r.info,
     mergedConfiguration.getGlobalConfiguration(),
     mergedConfiguration.getOverrideConfiguration(), r.compat,
     r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
     r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
     dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
     r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));

   final ActivityLifecycleItem lifecycleItem;
   if (andResume) {
    lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
   } else {
    lifecycleItem = PauseActivityItem.obtain();
   }
   clientTransaction.setLifecycleStateRequest(lifecycleItem);
   //  clientTransaction
   mService.getLifecycleManager().scheduleTransaction(clientTransaction);
   ...
}
Client Transaction 은 Activity 의 시작 정 보 를 관리 합 니 다.Client LifecycleManager 에서 실 행 됩 니 다.scheduleTransaction 방법 에서 EXECUTE 를 보 냈 습 니 다.TRANSACTION 의 메 시 지 는 Activity Thread 의 H 클래스 에 처리 한 다음 TransactionExecutor.execute()를 실행 한 다음 handle LaunchActivity 방법 을 실행 합 니 다.다음 과 같 습 니 다.

 void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
  final IApplicationThread client = transaction.getClient();
  transaction.schedule();
  ...
 }

 public void schedule() throws RemoteException {
  mClient.scheduleTransaction(this);
 }

 void scheduleTransaction(ClientTransaction transaction) {
  transaction.preExecute(this);
  sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
 }

 class H extends Handler {
   ...
   public void handleMessage(Message msg) {
   ...
   case EXECUTE_TRANSACTION:
    final ClientTransaction transaction = (ClientTransaction) msg.obj;
    mTransactionExecutor.execute(transaction);
    if (isSystem()) {
     transaction.recycle();
    }
    break;
   ...
   } 
   ...
 }

 public void execute(ClientTransactionHandler client, IBinder token,
   PendingTransactionActions pendingActions) {
  ...
  client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
 }
다음은 Activity Thread 에서 후속 작업 을 처리 합 니 다.

public Activity handleLaunchActivity(ActivityClientRecord r,
   PendingTransactionActions pendingActions, Intent customIntent) {
  ...
  final Activity a = performLaunchActivity(r, customIntent);
  ...
  return a;
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  ContextImpl appContext = createBaseContextForActivity(r);
  ...
  java.lang.ClassLoader cl = appContext.getClassLoader();
  activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
  ...
  Application app = r.packageInfo.makeApplication(false, mInstrumentation);
  ...
  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, window, r.configCallback,
      r.assistToken);
  ...
  activity.setTheme(theme);
  ...
  mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
}
perform LaunchActivity 방법 에서 주로 다음 과 같은 몇 가지 일 을 했 습 니 다.
  • activity 를 시작 할 컨 텍스트 환경 만 들 기
  • Instrumentation 의 new Activity 방법 을 통 해 반사 형식 으로 activity 인 스 턴 스 를 만 듭 니 다
  • 애플 리 케 이 션 이 존재 하지 않 으 면 애플 리 케 이 션 을 만 들 고 애플 리 케 이 션 의 onCreate 방법 을 호출 합 니 다
  • Activity 를 초기 화하 고 Window 대상(Phone Window)을 만 들 고 Activity 와 Window 의 연결 을 실현 합 니 다
  • Instrumentation 을 통 해 Activity 의 onCreate 방법 을 호출 합 니 다.
  • 총결산
    루트 Activity 는 전체적으로 학습 의미 가 크 므 로 전체적인 절차 에 착안 하여 절차 가 통 하지 않 을 때 debug 를 할 수 있 습 니 다.Activity 의 전체 시작 프로 세 스:
  • 아이콘 을 클릭 하고 Launcher 가 AMS 에 앱 시작 을 요청 합 니 다
  • AMS 피드백 이 시작 요청 을 받 고 Launcher 에 게 pause 상태 로 들 어 갔다 고 알려 줍 니 다
  • Launcher 가 일시 정지 상태 에 들 어가 AMS
  • 에 알 립 니 다.
  • AMS 는 새로운 앱 이 시작 되 었 는 지 확인 합 니 다.그렇지 않 으 면 Zygote 에 새로운 프로 세 스 를 만 들 고 Activity Thread.main()
  • 을 시작 하 라 고 알 립 니 다.
  • 응용 프로 세 스 시작 ActivityThread
  • Activity Thread 에서 H 처리 가 Activity 를 시작 해 야 한 다 는 요청 메시지
  • 이상 은 안 드 로 이 드 액 티 비 티 의 시작 프로 세 스 에 대한 상세 한 내용 입 니 다.안 드 로 이 드 액 티 비 티 의 시작 프로 세 스 에 관 한 자 료 는 다른 관련 글 을 주목 하 세 요!

    좋은 웹페이지 즐겨찾기