An overview of the
When an App is started, it goes through the following steps
- The first step is to click on the App icon
Launcher
Process, throughActivityManagerService
Binder IPC form tosystem_server
The process bystartActivity
The request of system_server
After receiving the request, the process passesProcess.start
Methods tozygote
A process sends a request to create a processzygote
processfork
Produces a new child process, i.eApp
process- Then enter the
ActivityThread.main
Method, which runs in theApp
In process, passActivityManagerService
Binder IPC form tosystem_server
The process byattachApplication
request system_server
After receiving the request, perform a series of preparatory work before submitting the request through Binder IPCApp
The process to sendscheduleLaunchActivity
requestApp
processBinder Threads (ApplicationThreads)
After receiving the request, passHandler
Send to the main threadLAUNCH_ACTIVITY
The message- After the main thread receives the Message, it creates the target through reflection
Activity
And the callbackActivity
theonCreate
The start of our ContentProvider is in the fourth step of attachApplication. Here we look at the source code
ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final longorigId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid, callingUid, startSeq); Binder.restoreCallingIdentity(origId); }}Copy the code
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {... thread.bindApplication(processName, appInfo, providers, app.instr.mClass, profilerInfo, app.instr.mArguments, app.instr.mWatcher, app.instr.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.persistent,new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
Copy the code
The bindApplication method of thread is called. Thread is of type IApplicationThread, a binder used for cross-process communication, and the implementation class is the inner class ApplicationThread of ActivityThread
ApplicationThread.java
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, 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, boolean autofillCompatibilityEnabled) {... sendMessage(H.BIND_APPLICATION, data); }Copy the code
This method actually ends up sending a BIND_APPLICATION message to the inner class H of ActivityThread
ActivityThread.java
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
Copy the code
This method calls the handleBindApplication method
private void handleBindApplication(AppBindData data) {...finalInstrumentationInfo ii; .// Create the mInstrumentation instance
if(ii ! =null) {.../ / create ContextImpl
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
// Create the mInstrumentation instance
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch(Exception e) { ... }... }else {
mInstrumentation = newInstrumentation(); }... Application app; .try{...// Create Application instance
app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if(! data.restrictedBackupMode) {if(! ArrayUtils.isEmpty(data.providers)) {/ / start the ContentProvider
installContentProviders(app, data.providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); }}try {
// Call Application onCreate
mInstrumentation.callApplicationOnCreate(app);
} catch(Exception e) { ... }}finally{... }... }Copy the code
Let’s analyze the method from the top down
- I first created
ContextImpl
object - And then create
mInstrumentation
object - And then I create
Application
object - And then it starts
ContentProvider
- And then finally called
Application
The object’sonCreate
We found that the ContentProvider is already started before calling onCreate of the Application. This can also be used as part of the startup optimization. If the ContentProvider is not needed, we recommend removing it because it will automatically start. I tested it with TraceView before, and it takes about 5ms, but no matter how small the mosquito is, it is still meat
Let’s move on to the installContentProviders method
private void installContentProviders( Context context, List
providers)
{
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
/ / comment 1
for (ProviderInfo cpi : providers) {
if (DEBUG_PROVIDER) {
StringBuilder buf = new StringBuilder(128);
buf.append("Pub ");
buf.append(cpi.authority);
buf.append(":");
buf.append(cpi.name);
Log.i(TAG, buf.toString());
}
/ / comment 2
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/.true /*noReleaseNeeded*/.true /*stable*/);
if(cph ! =null) {
cph.noReleaseNeeded = true; results.add(cph); }}try {
/ / comment 3
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throwex.rethrowFromSystemServer(); }}Copy the code
- At comment 1, iterate over the current application’s
ProviderInfo
List, get eachContentProvider
theProviderInfo
(storageContentProvider
The information) - At comment 2, call
installProvider
To start theContentProvider
- through
AMS
thepublishContentProviders
Method, take theseContentProvider
Store toAMS
themProviderMap
, play the role of cache, to prevent repeated calls
Let’s move on to the installProvider method
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {.../ / comment 1
final java.lang.ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true); localProvider = cl.loadClass(className).newInstance(); provider = localProvider.getIContentProvider(); .../ / comment 2
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
if(! mInstrumentation.onException(null, e)) {
throw new RuntimeException(
"Unable to get provider " + info.name
+ ":"+ e.toString(), e); }}Copy the code
- At comment 1, create by reflection
ContentProvider
- At comment 2, it is called
ContentProvider
theattachInfo
methods
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
if(info ! =null) { setReadPermission(info.readPermission); setWritePermission(info.writePermission); setPathPermissions(info.pathPermissions); mExported = info.exported; mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) ! =0;
setAuthorities(info.authority);
}
ContentProvider.this.onCreate(); }}Copy the code
This method calls onCreate of the ContentProvider, where the startup of the ContentProvider is complete
Reference: Advanced Android Decryption