Source based on Android 10
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
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);
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
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