I think this should be a lot of people to discuss, I 13 years when the framework has been made, you can run 80% apk, but I am more lazy has not been to write a summary of some of these ideas, today to share with you,
Similar Items http://git.oschina.net/lody/Direct-load-apk
First, let's explore how an APK is started,
OK, first you have to install this apk, then you click on the icon, the result apk will start, see the screen, complete.
First question: What did the system do when I clicked the apk icon?
Open Logcat Create a new filter to Activitymanager as Tag, empty Logcat, click the apk icon, you can see the following log:
The first log is the start activity,intent content:
Action=android.intent.action.main
Category=android.intent.category.launcher,
So you understand why your main Activity needs to be configured like this.
The second log is the START process,
So click on the APK image after the system has done 2 things: 1. Start a process; 2. Start the main activity in this process
But what we are going to talk about today is not to install APK boot, do not install how to start, there must be an entrance to me,
Yes we need a host: Imagine a File manager, click the apk in the list to launch directly, this file manager is our host,
Do you have to ask if you can not host it?
The answer is, no, I have no way, no entrance you how to operate!
The question we are going to discuss here is how the host implements the APK direct boot function.
Second question: How the host implements the APK direct boot function
In the first question we've explained how the APK starts, so what we need to do is simulate what the system does.
First of all, start apk boot What, an activity, so good we never installed APK Androidmanifest.xml parse out start Activity, then call startactivity not OK, sorry, crash, Activity not in Androidmanifest.xml Configuration!
So we can only start an activity that's already configured in a re-host,
Scrutiny how the activity starts, grabs the root, startactivity the final implementation of the call is (don't ask me how to find it in the Android.app.Instrumentation line 1419th)
int result = Activitymanagernative.getdefault () . StartActivity (Whothread, Who.getbasepackagename (), intent, intent.resolvetypeifneeded (Who.getcontentresolver ()), token, Target! = null? Target.mEmbeddedID:null, requestcode, 0, NULL, NULL, options);
This method is directly transferred to the Activitymanagerservice (AMS) system process, after the response, and then back to the application process, callback to Activitythread internal Handler H:
Case launch_activity: { trace.tracebegin (Trace.trace_tag_activity_manager, "Activitystart"); Activityclientrecord r = (activityclientrecord) msg.obj; R.packageinfo = Getpackageinfonocheck ( r.activityinfo.applicationinfo, r.compatinfo); Handlelaunchactivity (R, NULL); Trace.traceend (Trace.trace_tag_activity_manager); } Break
Android.app.ActivityThread.handleLaunchActivity (Activityclientrecord R, Intent customintent) line:2217
Android.app.ActivityThread.performLaunchActivity (Activityclientrecord R, Intent customintent) line:2077
Activity activity = NULL; try { Java.lang.ClassLoader cl = R.packageinfo.getclassloader (); Activity = minstrumentation.newactivity ( cl, Component.getclassname (), r.intent);
Public Activity newactivity (ClassLoader cl, String className, Intent Intent) throws Instantiationexception, Illegalaccessexception, classnotfoundexception { return (Activity) Cl.loadclass (className). newinstance (); }
The idea is simple, create activity objects through reflection, notice oh this is the application process, smart you may think of, start a host configuration of activity, callback to create the activity object when the real activity object is not OK?
Let's explore how this is achieved,
First, we start the activity need to pass a Intent object, AMS used to find the activity component, the Performlaunchactivity method's R parameter contains a Intent object, this Intent is Startactivit Y () method (which is very critical),
1. Use dynamic proxy to intercept Activitymanagernative's StartActivity method:
(As for the Java dynamic Agent technology itself Baidu) to determine the Intent parameters, if the Activity to start is not installed apk, then replace him with the host has been declared,
Private Intent Makeproxy (Intent ointent, String proxyclass) {Intent Intent = new Intent (); Intent.setclassname ( Apkrunner.getshellpkg (), proxyclass); Intent.putextra (Flag_proxy, True); Intent.putextra (Key_intent, oIntent);/** * Add logo in the past will lead to some inexplicable problems, we will default to him to start a good 2014-4-3 *///intent.addflags (Ointent.getflags ()); return intent;}
Storing the original Intent as a parameter to the Intent,
2. Intercept Activitythread H's handlemessage (Message msg) method:
Replaces Handler's callback object with reflection.
H The original callback object is NULL, so your callback-a Boolean handlemessage (Message msg) returns false to let the system call the original version.
In launch_activity message substitution (Activityclientrecord R) R.activityinfo and R.intent
Activityinfo object's role, see this line 2808
R.packageinfo = Getpackageinfo (ainfo.applicationinfo
This line of code creates a loadedapk object, which is very critical, an apk loaded after all the information is stored on this object (such as: Dexclassloader, Resources, application), a package corresponding to an object, the package name difference, and Activitythread is designed to cache N loadedapk, which is stored in a map with the package name key. See part of the code for the Getpackageinfo method:
PackageInfo = New loadedapk (This, Ainfo, Compatinfo, Baseloader, securityviolation, Includecode && (ainfo.flags&applicationinfo.flag_has_code)! = 0); if (includecode) { mpackages.put (ainfo.packagename, new weakreference<loadedapk> (PackageInfo)); } else { mresourcepackages.put (ainfo.packagename, new weakreference<loadedapk> (PackageInfo)); }
So, we need to replace R.activityinfo, Activityinfo use Packagemanager getpackagearchiveinfo to create
The next step is to create a few key objects loadedapk:
- 1.ClassLoader Code Manager
ANDROID.APP.LOADEDAPK Line 318
Mclassloader = Applicationloaders.getdefault (). getClassLoader ( zip, LibraryPath, mbaseclassloader); ............. Pathclassloader Pathclassloader = new Pathclassloader (zip, parent); Trace.traceend (Trace.trace_tag_activity_manager); return pathclassloader;
If using Pathclassloader to create is not feasible, fortunately Android opened a dexclassloader to us, so we want to replace the Mclassloader object with reflection after loadedapk creation
ANDROID.APP.LOADEDAPK Line 318
Public Resources getresources (Activitythread mainthread) { if (mresources = = null) { mresources = Mainthread.gettoplevelresources (Mresdir, display.default_display, NULL, this); } return mresources; }
Assetmanager assets = new Assetmanager (); if (Assets.addassetpath (resdir) = = 0) { return null; } ... R = new Resources (assets, DM, config, compatinfo, token);
So you know how to create an apk for the Resources, right, the key point is Assets.addassetpath (Resdir)
After creating the Resources, replace the loadedapk mresources object
- 3.Application the first component created by each APK launch is application
ANDROID.APP.LOADEDAPK Line 486
Public Application Makeapplication (Boolean forcedefaultappclass, instrumentation instrumentation) { if ( Mapplication! = null) { return mapplication; } Application app = null; String appclass = mapplicationinfo.classname; if (Forcedefaultappclass | | (Appclass = = null)) { Appclass = "android.app.Application"; } try { Java.lang.ClassLoader cl = getClassLoader (); Contextimpl AppContext = Contextimpl.createappcontext (Mactivitythread, this); App = MActivityThread.mInstrumentation.newApplication ( cl, Appclass, appContext); Appcontext.setoutercontext (app); } catch (Exception e) { } mActivityThread.mAllApplications.add (app); Mapplication = app;
There's no difficulty in creating this.
After the Application object is done, we simulate call the OnCreate () method, OK, an apk run the necessary environment to build,
The next step is to use the rescue method to start the APK's main activity.
Of course, it's hard to explain the implementation of this framework, and there's a lot of detail to deal with.
But that's the principle, rescue!
Let's talk about this today, the framework source will be released.
direct-run-apk Apk Free Install direct start principle and implementation (i)