Skip to content

Commit c5e3a88

Browse files
committed
Optimized reflection APIs.
1 parent 832b175 commit c5e3a88

File tree

18 files changed

+884
-554
lines changed

18 files changed

+884
-554
lines changed

AndroidStub/src/main/aidl/android/app/IServiceConnection.aidl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import android.content.ComponentName;
2121

2222
/** @hide */
2323
oneway interface IServiceConnection {
24-
void connected(in ComponentName name, IBinder service);
24+
// void connected(in ComponentName name, IBinder service);
2525

2626
/** Added in Android O */
27-
//void connected(in ComponentName name, IBinder service, boolean dead);
27+
void connected(in ComponentName name, IBinder service, boolean dead);
2828
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package android.app;
2+
3+
import android.content.ComponentName;
4+
import android.content.Context;
5+
import android.content.Intent;
6+
import android.os.Bundle;
7+
import android.os.IBinder;
8+
import android.os.PersistableBundle;
9+
10+
/**
11+
* Created by qiaopu on 2018/5/7.
12+
*/
13+
public class Instrumentation {
14+
15+
public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
16+
throw new RuntimeException("Stub!");
17+
}
18+
19+
public void callApplicationOnCreate(Application app) {
20+
throw new RuntimeException("Stub!");
21+
}
22+
23+
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
24+
throw new RuntimeException("Stub!");
25+
}
26+
27+
public void callActivityOnCreate(Activity activity, Bundle icicle) {
28+
throw new RuntimeException("Stub!");
29+
}
30+
31+
public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {
32+
throw new RuntimeException("Stub!");
33+
}
34+
35+
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) {
36+
throw new RuntimeException("Stub!");
37+
}
38+
39+
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
40+
throw new RuntimeException("Stub!");
41+
}
42+
43+
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment target, Intent intent, int requestCode, Bundle options) {
44+
throw new RuntimeException("Stub!");
45+
}
46+
47+
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, String target, Intent intent, int requestCode, Bundle options) {
48+
throw new RuntimeException("Stub!");
49+
}
50+
51+
public Context getContext() {
52+
throw new RuntimeException("Stub!");
53+
}
54+
55+
public Context getTargetContext() {
56+
throw new RuntimeException("Stub!");
57+
}
58+
59+
public ComponentName getComponentName() {
60+
throw new RuntimeException("Stub!");
61+
}
62+
63+
public static final class ActivityResult {
64+
public ActivityResult(int resultCode, Intent resultData) {
65+
throw new RuntimeException("Stub!");
66+
}
67+
}
68+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package android.app;
2+
3+
/**
4+
* Created by qiaopu on 2018/4/25.
5+
*/
6+
public class ResourcesManager {
7+
8+
public static ResourcesManager getInstance() {
9+
throw new RuntimeException("Stub!");
10+
}
11+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package android.content;
2+
3+
import android.net.Uri;
4+
import android.os.Bundle;
5+
import android.support.annotation.NonNull;
6+
import android.support.annotation.Nullable;
7+
8+
/**
9+
* Created by qiaopu on 2018/5/7.
10+
*/
11+
public abstract class ContentResolver {
12+
13+
public ContentResolver(Context context) {
14+
throw new RuntimeException("Stub!");
15+
}
16+
17+
public final @Nullable
18+
Bundle call(@NonNull Uri uri, @NonNull String method,
19+
@Nullable String arg, @Nullable Bundle extras) {
20+
throw new RuntimeException("Stub!");
21+
}
22+
23+
protected abstract IContentProvider acquireProvider(Context c, String name);
24+
25+
protected IContentProvider acquireExistingProvider(Context c, String name) {
26+
throw new RuntimeException("Stub!");
27+
}
28+
29+
public abstract boolean releaseProvider(IContentProvider icp);
30+
31+
protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
32+
33+
public abstract boolean releaseUnstableProvider(IContentProvider icp);
34+
35+
public abstract void unstableProviderDied(IContentProvider icp);
36+
37+
public void appNotRespondingViaProvider(IContentProvider icp) {
38+
throw new RuntimeException("Stub!");
39+
}
40+
}

CoreLibrary/build.gradle

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import com.android.build.gradle.api.ApplicationVariant
2+
import com.android.build.gradle.api.LibraryVariant
3+
import com.google.common.base.Joiner
4+
15
apply plugin: 'com.android.library'
26

37
android {
@@ -29,12 +33,31 @@ repositories {
2933
jcenter()
3034
}
3135

36+
final String projectAndroidStub = ':AndroidStub'
37+
3238
dependencies {
3339
compile fileTree(dir: 'libs', include: ['*.jar'])
3440

35-
provided project(':AndroidStub')
41+
provided project(projectAndroidStub)
3642

3743
testCompile 'junit:junit:4.12'
3844
}
3945

46+
// Using Stub classes first when compiling.
47+
afterEvaluate {
48+
project.android.libraryVariants.each { LibraryVariant variant ->
49+
variant.javaCompile.doFirst { JavaCompile javaCompile ->
50+
String projectAndroidStubPath = project.project(projectAndroidStub).projectDir.canonicalPath
51+
// println "projectAndroidStubPath: ${projectAndroidStubPath}"
52+
File stubPath = javaCompile.classpath.find {
53+
it.canonicalPath.startsWith(projectAndroidStubPath)
54+
}
55+
if (stubPath == null) {
56+
throw new RuntimeException("reset bootclasspath error.")
57+
}
58+
javaCompile.options.setBootClasspath(Joiner.on(File.pathSeparator).join(stubPath, javaCompile.options.bootClasspath))
59+
}
60+
}
61+
}
62+
4063
apply from: 'upload.gradle'
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package android.content;
2+
3+
import android.annotation.TargetApi;
4+
import android.os.Build;
5+
6+
/**
7+
* Wrapper of {@link ContentResolver}
8+
* Created by qiaopu on 2018/5/7.
9+
*/
10+
public abstract class ContentResolverWrapper extends ContentResolver {
11+
12+
ContentResolver mBase;
13+
14+
public ContentResolverWrapper(Context context) {
15+
super(context);
16+
mBase = context.getContentResolver();
17+
}
18+
19+
@Override
20+
protected IContentProvider acquireProvider(Context context, String auth) {
21+
return mBase.acquireProvider(context, auth);
22+
}
23+
24+
@Override
25+
protected IContentProvider acquireExistingProvider(Context context, String auth) {
26+
return mBase.acquireExistingProvider(context, auth);
27+
}
28+
29+
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
30+
@Override
31+
protected IContentProvider acquireUnstableProvider(Context context, String auth) {
32+
return mBase.acquireUnstableProvider(context, auth);
33+
}
34+
35+
@Override
36+
public boolean releaseProvider(IContentProvider icp) {
37+
return mBase.releaseProvider(icp);
38+
}
39+
40+
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
41+
@Override
42+
public boolean releaseUnstableProvider(IContentProvider icp) {
43+
return mBase.releaseUnstableProvider(icp);
44+
}
45+
46+
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
47+
@Override
48+
public void unstableProviderDied(IContentProvider icp) {
49+
mBase.unstableProviderDied(icp);
50+
}
51+
52+
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
53+
@Override
54+
public void appNotRespondingViaProvider(IContentProvider icp) {
55+
mBase.appNotRespondingViaProvider(icp);
56+
}
57+
58+
}

CoreLibrary/src/main/java/com/didi/virtualapk/PluginManager.java

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,25 @@
2828
import android.content.Intent;
2929
import android.content.pm.ProviderInfo;
3030
import android.content.pm.ResolveInfo;
31-
import android.databinding.DataBinderMapperProxy;
3231
import android.net.Uri;
3332
import android.os.Build;
33+
import android.os.Handler;
3434
import android.util.Log;
3535
import android.util.Singleton;
3636

37-
import com.didi.virtualapk.delegate.IContentProviderProxy;
38-
import com.didi.virtualapk.internal.PluginContentResolver;
3937
import com.didi.virtualapk.delegate.ActivityManagerProxy;
38+
import com.didi.virtualapk.delegate.IContentProviderProxy;
4039
import com.didi.virtualapk.internal.ComponentsHandler;
4140
import com.didi.virtualapk.internal.LoadedPlugin;
41+
import com.didi.virtualapk.internal.PluginContentResolver;
4242
import com.didi.virtualapk.internal.VAInstrumentation;
4343
import com.didi.virtualapk.utils.PluginUtil;
44-
import com.didi.virtualapk.utils.ReflectUtil;
44+
import com.didi.virtualapk.utils.Reflector;
4545
import com.didi.virtualapk.utils.RunUtil;
4646

4747
import java.io.File;
48-
import java.io.FileNotFoundException;
48+
import java.io.FileInputStream;
49+
import java.io.InputStream;
4950
import java.lang.reflect.Field;
5051
import java.util.ArrayList;
5152
import java.util.Iterator;
@@ -94,7 +95,6 @@ private PluginManager(Context context) {
9495
}
9596

9697
private void prepare() {
97-
Systems.sHostContext = getHostContext();
9898
this.hookInstrumentationAndHandler();
9999
this.hookSystemServices();
100100
hookDataBindingUtil();
@@ -114,16 +114,16 @@ private void doInWorkThread() {
114114
}
115115

116116
private void hookDataBindingUtil() {
117-
try {
118-
Class cls = Class.forName("android.databinding.DataBindingUtil");
119-
Object old = ReflectUtil.getField(cls, null, "sMapper");
120-
Callback callback = new DataBinderMapperProxy(old);
121-
ReflectUtil.setField(cls, null, "sMapper", callback);
122-
123-
addCallback(callback);
124-
125-
} catch (Exception e) {
126-
e.printStackTrace();
117+
Reflector.QuietReflector reflector = Reflector.QuietReflector.on("android.databinding.DataBindingUtil").field("sMapper");
118+
Object old = reflector.get();
119+
if (old != null) {
120+
try {
121+
Callback callback = Reflector.on("android.databinding.DataBinderMapperProxy").constructor().newInstance();
122+
reflector.set(callback);
123+
addCallback(callback);
124+
} catch (Reflector.ReflectedException e) {
125+
e.printStackTrace();
126+
}
127127
}
128128
}
129129

@@ -144,14 +144,14 @@ private void hookSystemServices() {
144144
Singleton<IActivityManager> defaultSingleton;
145145

146146
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
147-
defaultSingleton = (Singleton<IActivityManager>) ReflectUtil.getField(ActivityManager.class, null, "IActivityManagerSingleton");
147+
defaultSingleton = Reflector.on(ActivityManager.class).field("IActivityManagerSingleton").get();
148148
} else {
149-
defaultSingleton = (Singleton<IActivityManager>) ReflectUtil.getField(ActivityManagerNative.class, null, "gDefault");
149+
defaultSingleton = Reflector.on(ActivityManagerNative.class).field("gDefault").get();
150150
}
151151
IActivityManager activityManagerProxy = ActivityManagerProxy.newInstance(this, defaultSingleton.get());
152152

153153
// Hook IActivityManager from ActivityManagerNative
154-
ReflectUtil.setField(defaultSingleton.getClass().getSuperclass(), defaultSingleton, "mInstance", activityManagerProxy);
154+
Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy);
155155

156156
if (defaultSingleton.get() == activityManagerProxy) {
157157
this.mActivityManager = activityManagerProxy;
@@ -163,16 +163,18 @@ private void hookSystemServices() {
163163

164164
private void hookInstrumentationAndHandler() {
165165
try {
166-
Instrumentation baseInstrumentation = ReflectUtil.getInstrumentation(this.mContext);
166+
ActivityThread activityThread = ActivityThread.currentActivityThread();
167+
Instrumentation baseInstrumentation = activityThread.getInstrumentation();
167168
if (baseInstrumentation.getClass().getName().contains("lbe")) {
168169
// reject executing in paralell space, for example, lbe.
169170
System.exit(0);
170171
}
171-
172+
172173
final VAInstrumentation instrumentation = new VAInstrumentation(this, baseInstrumentation);
173-
Object activityThread = ReflectUtil.getActivityThread(this.mContext);
174-
ReflectUtil.setInstrumentation(activityThread, instrumentation);
175-
ReflectUtil.setHandlerCallback(this.mContext, instrumentation);
174+
175+
Reflector.with(activityThread).field("mInstrumentation").set(instrumentation);
176+
Handler mainHandler = Reflector.with(activityThread).method("getHandler").call();
177+
Reflector.with(mainHandler).field("mCallback").set(instrumentation);
176178
this.mInstrumentation = instrumentation;
177179
} catch (Exception e) {
178180
e.printStackTrace();
@@ -185,8 +187,8 @@ private void hookIContentProviderAsNeeded() {
185187
try {
186188
Field authority = null;
187189
Field mProvider = null;
188-
ActivityThread activityThread = (ActivityThread) ReflectUtil.getActivityThread(mContext);
189-
Map mProviderMap = (Map) ReflectUtil.getField(activityThread.getClass(), activityThread, "mProviderMap");
190+
ActivityThread activityThread = ActivityThread.currentActivityThread();
191+
Map mProviderMap = Reflector.with(activityThread).field("mProviderMap").get();
190192
Iterator iter = mProviderMap.entrySet().iterator();
191193
while (iter.hasNext()) {
192194
Map.Entry entry = (Map.Entry) iter.next();
@@ -230,7 +232,9 @@ public void loadPlugin(File apk) throws Exception {
230232
}
231233

232234
if (!apk.exists()) {
233-
throw new FileNotFoundException(apk.getAbsolutePath());
235+
// throw the FileNotFoundException by opening a stream.
236+
InputStream in = new FileInputStream(apk);
237+
in.close();
234238
}
235239

236240
LoadedPlugin plugin = LoadedPlugin.create(this, this.mContext, apk);

0 commit comments

Comments
 (0)