Android 10 startActivity source code analysis

Source based on Android 10

Android 10.0 startActivity flowchart

This figure focuses on refining some of the life cycle, Android 10 added a ActivityTaskManager, designed to manage Activity, took over part of the work of ActivityManager

Understand Instrumentation

Activity will first go through calling Instrumentation, Instrumentation contains callActivityOnCreate, callActivityOnPause, callApplicationOnCreate and other calls, with powerful tracking Activity and Application life cycle, it is also used as bases for application testing framework to use. A process has a ActivityThread objects, object holds a ActivityThread Instrumentation objects, each Activity are in possession of Instrumentation

IPC happen Where?

In the Instrumentation enter through the interface from the App IActivityTaskManager.aidl process to system_server process; Back App process by the system_server by IApplicationThread.aidl interface in ClientTransaction

Activity is how to manage the stack?

ActivityRecord: Activity ActivityRecord form to record a ActivityRecord corresponds to an Activity instance
TaskRecord: This is a real Activity stack has an internal ArrayList <ActivityRecord>, the current stack records all Activity
ActivityStack: Activity is responsible for managing the stack, multi-store a TaskRecord

Activity in the node where to read the boot mode configuration manifest

Reading the configuration of FIG manifest

Figure returned by PackageManagerService # resolveIntentInternal method ResolveInfo, ResolveInfo including ActivityInfo, ServiceInfo, ProviderInfo and other information, this call is already in the process system_server, so it is not IPC, PackageManagerService mainly responsible for parsing AndroidManifest.xml, apk scan local directory, delete the installation Management App Wait

Where detect Activity is registered in the manifest?

The key code ActivityStarter # startActivity methods:

       if (err == ActivityManager.START_SUCCESS && aInfo == null) {
           // We couldn't find the specific class specified in the Intent.
           // Also the end of the line.
           err = ActivityManager.START_CLASS_NOT_FOUND;
       }

aInfo is ActivityInfo, and ActivityInfo empty cause subsequent error is returned. That is aInfo come from? Of course, it is parsed by PackageManagerService # resolveIntentInternal method. Then detected Instrumentation # checkStartActivityResult method to return value after ActivityManager.START_CLASS_NOT_FOUND, throw "Unable to find explicit activity class {xxx};? Have you declared this activity in your AndroidManifest.xml" anomaly

Why not take effect individually configured taskAffinity

The key code ActivityStarter # startActivityUnchecked methods:

  if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
         newTask = true;
         result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
  } else if (mSourceRecord != null) {
         result = setTaskFromSourceRecord();
  } else if (mInTask != null) {
         result = setTaskFromInTask();
  } else {
         result = setTaskToCurrentTopOrCreateNewTask();
  }

Only mLaunchFlags marked FLAG_ACTIVITY_NEW_TASK will go to create a new Activity stack that is TaskRecord, and the system did not do a deal with the situation alone configuration of taskAffinity. That launchMode configured in AndroidManifest.xml is where the process, and in response to mLaunchFlags it?
ActivityStarter # startActivityUnchecked method called ActivityStarter # computeLaunchingTaskFlags method configured mLaunchFlags code is as follows:

   if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
         Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                        "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
         mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    }else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
         mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
         mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    }

You can see LAUNCH_SINGLE_INSTANCE mode starts in a new stack and so we are already well-known rules

Understanding ClientTransactionItem and ActivityLifecycleItem

ClientLifecycleManager one or more lifecycle events can be grouped together as that is ClientTransaction to execute a transaction, onCreate new Activity when startActivity, onStart, onResume event is executed is stored in a transaction

New Activity onCreate event of startActivity when stored in a member variable ClientTransaction of List <ClientTransactionItem> type, the carrier is LaunchActivityItem. LaunchActivityItem also ClientTransactionItem sub-categories, namely start Activity events. Another NewIntentItem (onNewIntent trigger callback), ActivityResultItem (trigger onActivityResult), ConfigurationChangeItem (onConfigurationChanged trigger callback) and other events

When startActivity new Activity of onResume events stored in the variable member variables ClientTransaction of ActivityLifecycleItem type, this variable also represents the final state of the life cycle of the carrier is ResumeActivityItem. ActivityLifecycleItem also ClientTransactionItem of a subclass

Why not do the time-consuming operation onPause method Activity in?

ClientTransaction is Parcelable data, sent to the terminal by scheduleTransaction App IApplicationThread.aidl method, and then added to the main thread ActivityThread.H message queue for execution. The former will in turn send a new Activity Activity of pause and resume the transaction, and then both transactions happen in this order by ActivityThread.H startActivity time, we can not do time-consuming operation onPause method Activity, since only after the implementation method onPause life cycle events next Activity in order to be executed, otherwise block the new interface displays

activity instance is created where?

In ActivityThread # performLaunchActivity method will create an instance of an object Activity by Instrumentation # newActivity method, subsequently called onCreate method Instrumentation # callActivityOnCreate method of callback Activity

Click the icon to launch App Launcher

Launcher, click the icon to start is to call the same method startActivity, but you need to create a process, the key code in ActivityStackSupervisor # startSpecificActivityLocked methods:

   final WindowProcessController wpc =
           mService.getProcessController(r.processName, r.info.applicationInfo.uid);
   if (wpc != null && wpc.hasThread()) {
        //判断进程存在,继续启动
        realStartActivityLocked(r, wpc, andResume, checkConfig);
        return;
   }
   //进程不存在,创建进程
   final Message msg = PooledLambda.obtainMessage(
           ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
           r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
   mService.mH.sendMessage(msg);

startProcess flow chart

zygote process communication and adopted a Socket way, why not use a more secure, simply copy the data once it's binder? As a fertilized zygote Android process, the process created by fork method, while multi-threaded fork is not allowed, or because of Copy-on-Write mechanisms result in a deadlock, and the binder is based on multi-threaded run

In ProcessList # startProcessLocked method, passing the value "android.app.ActivityThread" of entryPoint parameters, follow-up will pass through the process of zygote, the zygote fork new process to succeed, ActivityThread # main function will be called the new process, namely App real boot entry

ActivityThread.main flow chart

In ActivityManagerService # attachApplicationLocked execution method in two key logic, to create Application Examples First Back App and callback process by IApplicationThread onCreate method; the second is to call ActivityTaskManagerService # attachApplication method, further to start Home Activity.
Start Activity and ordinary startActivity same, will be called to ActivityStackSupervisor # realStartActivityLocked method

Understanding ActivityThread and ApplicationThread

ActivityThread.main () method is to start the entry procedure, the main thread initializes Looper, processing messages in the ActivityThread.H. ApplicationThread is ActivityThread internal class that implements the interface to receive callbacks IApplicationThread.aidl AMS systems and services, and most of them are related to the tasks of the four components, it sends a message to the Handler ActivityThread.H, that is, switching from binder to the main thread thread processing

How to Start an unregistered Activity in the manifest?

Load manifest information and testing in system_server registration process, it can not interfere with detection logic. It is common practice in the manifest register a placeholder Activity, system_server process before entering the unregistered Activity Activity modify the placeholder, and then wait for the process to return from system_server then changes back to App Activity is not registered, and then to create, start , that need to hook two:

hook ActivityTaskManager:

final Field singletonField = ActivityTaskManager.class
             .getDeclaredField("IActivityTaskManagerSingleton");
singletonField.setAccessible(true);
Singleton singleton = (Singleton) singletonField.get(null);
final Object activityTaskManagerObject = singleton.get();
final Field mInstanceField = Singleton.class.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object value = Proxy.newProxyInstance(ActivityTaskManager.class.getClassLoader()
     , new Class[]{Class.forName("android.app.IActivityTaskManager")}
     , new InvocationHandler() {
           @Override
           public Object invoke(Object proxy,
                         Method method, Object[] args) throws Throwable {
              if ("startActivity".equals(method.getName())) {
                  Intent raw;
                  int index = 0;
                  for (int i = 0; i < args.length; i++) {
                     if (args[i] instanceof Intent) {
                        index = I;
                        break;
                     }
                  }
                  if (!(args[index] instanceof Intent)) throw new AssertionError();
                  raw = (Intent) args[index];
                  if (raw.getComponent().getClassName()
                         .equals("com.yinghao.test.UnRegisterActivity")) {
                      ntent newIntent = new Intent();
                      //将未注册的 UnRegisterActivity 替换为占位 FakeActivity
                      newIntent.setComponent(new ComponentName("com.yinghao.test", 
                                   FakeActivity.class.getName()));
                      //记录 UnRegisterActivity
                      newIntent.putExtra(EXTRA_TARGET_INTENT, raw); 
                      args[index] = newIntent;
                  }
              }
              return method.invoke(activityTaskManagerObject, args);
           }
});
mInstanceField.set(singleton, value);

hook ActivityThread:

ActivityThread activityThread = ActivityThread.currentActivityThread();
Field mH1 = activityThread.getClass().getDeclaredField("mH");
mH1.setAccessible(true);
final Handler mH = (Handler) mH1.get(activityThread);
Field mCallBackField = Handler.class.getDeclaredField("mCallback");
mCallBackField.setAccessible(true);
mCallBackField.set(mH, new Handler.Callback() {
 @Override
 public boolean handleMessage(Message msg) {
  try {
   if (msg.what == 159) { // ActivityThread.H.EXECUTE_TRANSACTION
    final ClientTransaction transaction = (ClientTransaction) msg.obj;
    Field mActivityCallbacksField = transaction
               .getClass().getDeclaredField("mActivityCallbacks");
    mActivityCallbacksField.setAccessible(true);
    List<ClientTransactionItem> clientTransactionItems = 
        (List<ClientTransactionItem>) mActivityCallbacksField.get(transaction);
    if (clientTransactionItems != null) {
     for (ClientTransactionItem c : clientTransactionItems) {
      if (c instanceof LaunchActivityItem) {
       //修正 Activity 启动事件实体 LaunchActivityItem
       LaunchActivityItem item = (LaunchActivityItem) c;
       Field intentField = item.getClass().getDeclaredField("mIntent");
       intentField.setAccessible(true);
       Intent intent = (Intent) intentField.get(item);
       Field mInfoField = item.getClass().getDeclaredField("mInfo");
       mInfoField.setAccessible(true);
       ActivityInfo aInfo = (ActivityInfo) mInfoField.get(item);
       Intent realIntent = intent.getParcelableExtra(EXTRA_TARGET_INTENT);
       if (realIntent != null) {
         //将占位 FakeActivity 改回未注册的 UnRegisterActivity
         intent.setComponent(realIntent.getComponent());
         aInfo.packageName = realIntent.getComponent().getPackageName();
         aInfo.name = realIntent.getComponent().getClassName();
       }
       }
     }
    }
   }
  } catch (Exception e) {

  }
  return false; //返回 false 正好可以让 ActivityThread 继续处理
 }
});

Unregistered Activity start to realize the premise must be startActivity have mastered the process, which is the plug of entry, various practical applications need to be compatible Android version

At last

With a problem to analyze, study the source code, it will naturally focus the main line

No public concern, Get more knowledge
Published 48 original articles · won praise 255 · views 540 000 +

Guess you like

Origin blog.csdn.net/yhaolpz/article/details/105347247