We do not actively declare the class of the Activity, so how does the system find the corresponding Activity for us? In fact, this is the same as the normal Activity startup process, except that the implementation of if / else is different.
The beginning of doubt
Have you ever thought about a question: where browser Open a web page in. There is a button on the web page that can be called by clicking App.
How can this effect be achieved? The browser is an app; Why can an app call up the pages of other apps?
When it comes to cross app page calls, can you think of a mechanism: Activity Implicit call?
Implicit start principle
When we need to call the pages of other app s, the API we use is implicit call.
For example, we have an app that declares such an Activity:
<activity android:name=".OtherActivity" android:screenOrientation="portrait"> <intent-filter> <action android:name="mdove"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
If other apps want to start the above Activity, just call the following:
val intent = Intent() intent.action = "mdove" startActivity(intent)
We do not actively declare the class of the Activity, so how does the system find the corresponding Activity for us? In fact, this is the same as the normal Activity startup process, except that the implementation of if / else is different.
Next, let's review the startup process of Activity. In order to avoid falling into details, we only expand the "familiar" classes and call stacks, mainly string processes.
Cross process
First of all, we must be clear: whether it is implicit startup or display startup; Whether you start an Activity inside the App or an Activity outside the App, it is cross process. For example, in our above example, if an App wants to start the page of another App, it involves at least three processes.
Note that a mobile phone without root cannot see the process hatched by the system. That is why some code can't break points.
Students who have followed startActivity() should be familiar with the following call process. After following up several methods, they will find that they have entered a class called ActivityTread.
What are the characteristics of the ActivityTread class? There is a main function, which is our main thread.
Soon we can see the call of a common class: Instrumentation:
// Activity.java public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); //Omit }
Note that mminstrumentation#execstartactivity () has a yellow input parameter, which is the internal class ApplicationThread in ActivityThread.
What are the characteristics of the ApplicationThread class? It implements iaapplicationthread Stub, that is, aidl's "client callback for cross process calls".
In addition, another famous call will be seen in miminstrumentation #execstartactivity():
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { //Omit ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); return null; }
When we click getService(), we will see a red marked IActivityManager class.
It is not a java file, but aidl file.
So activitymanager In essence, getservice () returns the "server side of the process" interface instance, that is:
ActivityManagerService
public class ActivityManagerService extends IActivityManager.Stub
So the execution goes to the system_process. Omit the code details and take a look at the calling stack:
From the above debug screenshot, we can see that we have obtained the relevant information of our target activity at this time.
Here we simplify the source code of the target class and directly introduce the conclusion:
PackageManagerService
This class is equivalent to parsing all apk s in the mobile phone and constructing their information into memory, such as the following figure:
Small tips: in the mobile phone directory, / data / system / packages XML, you can see the path, process name, permission and other information of all apk s.
Start a new process
The premise of opening the target Activity is that the process of the target Activity is started. Therefore, the first time you want to open the target Activity, you need to start the process.
The code to start the process is in the method to start the Activity:
resumeTopActivityInnerLocked->startProcessLocked.
Here we introduce another famous class: ZygoteInit. Simply put, the App process will be started through ZygoteInit.
ApplicationThread
After the process starts, continue to return to the start process of the target Activity. Here is still a series of systems_ Process, and then iaapplicationthread enters the target process.
Notice that the iaapplicationthread callback to the ActivityThread again here.
class H extends Handler { //Omit public void handleMessage(Message msg) { switch (msg.what) { case EXECUTE_TRANSACTION: final ClientTransaction transaction = (ClientTransaction) msg.obj; mTransactionExecutor.execute(transaction); //Omit break; case RELAUNCH_ACTIVITY: handleRelaunchActivityLocally((IBinder) msg.obj); break; } //Omit } } //Execute Callback public void execute(ClientTransaction transaction) { final IBinder token = transaction.getActivityToken(); executeCallbacks(transaction); }
The implementation of CallBack here is the corresponding implementation of LaunchActivityItem#execute():
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mIsForward, mProfilerInfo, client); client.handleLaunchActivity(r, pendingActions, null); }
At this point, we go to ActivityThread#handleLaunchActivity(), which also goes to our daily life cycle. The call stack is as follows:
The call chain in the above screenshot implies the process of Activity instantiation (reflection):
public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className, @Nullable Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return (Activity) cl.loadClass(className).newInstance(); }
3
Browser startup principle
The reflow page in Hello is a standard, and the browser evokes another instance of the App.
Interactive process
html tags have a href attribute, such as: < a href = "..." >.
A common usage: < a href = "`` https://www.baidu.com ``">. That is, click to jump to Baidu.
Because this is the front-end tag, relying on the implementation of the browser and its kernel, jumping to a web page seems to be "natural" (otherwise called what browser).
Of course, the process here is basically the same as that of android interaction: declare the Activity to be started by implicit call; Then < a href = "" > pass in the corresponding protocol (scheme). For example:
Front page:
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <a href="mdove1://Haha "> start OtherActivity</a> </body>
android statement:
<activity android:name=".OtherActivity" android:screenOrientation="portrait"> <intent-filter> <data android:host="haha" android:scheme="mdove1" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
Reasoning implementation
The browser can load scheme, which can be understood as the encapsulation of the browser kernel. So is it the browser kernel that wants android to support scheme parsing?
Obviously, it's impossible to make a mobile operating system and let the browser implement it. Isn't it a bit murderous.
Therefore, the probability can be guessed that it should be handled by the browser app in the mobile phone. Let's take a look at the browser based on this conjecture apk implementation.
Browser implementation
Based on / data / system / packages XML file, we can pull out the browser apk.
Then jadx decompile the browser Source code related to WebView in APK:
We can find that the processing of href comes from implicit jump, so everything is connected with the above process.
Epilogue
Leave a small question at the end: if I write a WebView to load a front-end page, can I jump implicitly?
Original link: https://mp.weixin.qq.com/s/vWZDgOB0oFSiQg305Qqwiw