From a80ce96258e59a994eba70c29df603f3df0090bb Mon Sep 17 00:00:00 2001 From: hiai <519177109@qq.com> Date: Tue, 19 Feb 2019 22:43:56 +0800 Subject: [PATCH] Fixed component matching mistake --- .../virtualapk/internal/LoadedPlugin.java | 257 +++++++++++------- 1 file changed, 153 insertions(+), 104 deletions(-) diff --git a/CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java b/CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java index 59962a6..95d403c 100644 --- a/CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java +++ b/CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java @@ -80,7 +80,7 @@ public class LoadedPlugin { protected File getDir(Context context, String name) { return context.getDir(name, Context.MODE_PRIVATE); } - + protected ClassLoader createClassLoader(Context context, File apk, File libsDir, ClassLoader parent) throws Exception { File dexOutputDir = getDir(context, Constants.OPTIMIZE_DIR); String dexOutputPath = dexOutputDir.getAbsolutePath(); @@ -108,16 +108,16 @@ protected Resources createResources(Context context, String packageName, File ap return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration()); } } - + protected PluginPackageManager createPluginPackageManager() { return new PluginPackageManager(); } - + public PluginContext createPluginContext(Context context) { if (context == null) { return new PluginContext(this); } - + return new PluginContext(this, context); } @@ -143,6 +143,17 @@ protected ResolveInfo chooseBestActivity(Intent intent, String s, int flags, Lis protected Map mProviders; // key is authorities of provider protected Map mInstrumentationInfos; + + public static final int TYPE_ACTIVITY = 1; + public static final int TYPE_SERVICE = 2; + public static final int TYPE_BROADCAST_RECEIVER = 3; + + + protected Map> mActivityMatchMap = new HashMap<>(); + protected Map> mServiceMatchMap = new HashMap<>(); + protected Map> mBroadcastReceiverMatchMap = new HashMap<>(); + + protected Application mApplication; public LoadedPlugin(PluginManager pluginManager, Context context, File apk) throws Exception { @@ -154,9 +165,9 @@ public LoadedPlugin(PluginManager pluginManager, Context context, File apk) thro this.mPackageInfo = new PackageInfo(); this.mPackageInfo.applicationInfo = this.mPackage.applicationInfo; this.mPackageInfo.applicationInfo.sourceDir = apk.getAbsolutePath(); - + if (Build.VERSION.SDK_INT >= 28 - || (Build.VERSION.SDK_INT == 27 && Build.VERSION.PREVIEW_SDK_INT != 0)) { // Android P Preview + || (Build.VERSION.SDK_INT == 27 && Build.VERSION.PREVIEW_SDK_INT != 0)) { // Android P Preview try { this.mPackageInfo.signatures = this.mPackage.mSigningDetails.signatures; } catch (Throwable e) { @@ -166,7 +177,7 @@ public LoadedPlugin(PluginManager pluginManager, Context context, File apk) thro } else { this.mPackageInfo.signatures = this.mPackage.mSignatures; } - + this.mPackageInfo.packageName = this.mPackage.packageName; if (pluginManager.getLoadedPlugin(mPackageInfo.packageName) != null) { throw new RuntimeException("plugin has already been loaded : " + mPackageInfo.packageName); @@ -199,6 +210,7 @@ public LoadedPlugin(PluginManager pluginManager, Context context, File apk) thro } this.mActivityInfos = Collections.unmodifiableMap(activityInfos); this.mPackageInfo.activities = activityInfos.values().toArray(new ActivityInfo[activityInfos.size()]); + initMatchMap(mPackage.activities, TYPE_ACTIVITY); // Cache services Map serviceInfos = new HashMap(); @@ -207,6 +219,7 @@ public LoadedPlugin(PluginManager pluginManager, Context context, File apk) thro } this.mServiceInfos = Collections.unmodifiableMap(serviceInfos); this.mPackageInfo.services = serviceInfos.values().toArray(new ServiceInfo[serviceInfos.size()]); + initMatchMap(mPackage.services, TYPE_SERVICE); // Cache providers Map providers = new HashMap(); @@ -223,7 +236,7 @@ public LoadedPlugin(PluginManager pluginManager, Context context, File apk) thro Map receivers = new HashMap(); for (PackageParser.Activity receiver : this.mPackage.receivers) { receivers.put(receiver.getComponentName(), receiver.info); - + BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance()); for (PackageParser.ActivityIntentInfo aii : receiver.intents) { this.mHostContext.registerReceiver(br, aii); @@ -231,7 +244,7 @@ public LoadedPlugin(PluginManager pluginManager, Context context, File apk) thro } this.mReceiverInfos = Collections.unmodifiableMap(receivers); this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]); - + initMatchMap(mPackage.receivers, TYPE_BROADCAST_RECEIVER); // try to invoke plugin's application invokeApplication(); } @@ -300,7 +313,7 @@ public void run() { } } }, true); - + if (temp[0] != null) { throw temp[0]; } @@ -392,7 +405,7 @@ protected Application makeApplication(boolean forceDefaultAppClass, Instrumentat if (forceDefaultAppClass || null == appClass) { appClass = "android.app.Application"; } - + this.mApplication = instrumentation.newApplication(this.mClassLoader, appClass, this.getPluginContext()); // inject activityLifecycleCallbacks of the host application mApplication.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksProxy()); @@ -411,31 +424,10 @@ public ResolveInfo resolveActivity(Intent intent, int flags) { } public List queryIntentActivities(Intent intent, int flags) { - ComponentName component = intent.getComponent(); - List resolveInfos = new ArrayList(); - ContentResolver resolver = this.mPluginContext.getContentResolver(); - - for (PackageParser.Activity activity : this.mPackage.activities) { - if (match(activity, component)) { - ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.activityInfo = activity.info; - resolveInfos.add(resolveInfo); - } else if (component == null) { - // only match implicit intent - for (PackageParser.ActivityIntentInfo intentInfo : activity.intents) { - if (intentInfo.match(resolver, intent, true, TAG) >= 0) { - ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.activityInfo = activity.info; - resolveInfos.add(resolveInfo); - break; - } - } - } - } - - return resolveInfos; + return queryComponent(intent, TYPE_ACTIVITY); } + public ResolveInfo resolveService(Intent intent, int flags) { List query = this.queryIntentServices(intent, flags); if (null == query || query.isEmpty()) { @@ -447,71 +439,127 @@ public ResolveInfo resolveService(Intent intent, int flags) { } public List queryIntentServices(Intent intent, int flags) { - ComponentName component = intent.getComponent(); + return queryComponent(intent, TYPE_SERVICE); + } + + + public List queryBroadcastReceivers(Intent intent, int flags) { + return queryComponent(intent, TYPE_BROADCAST_RECEIVER); + } + + public ProviderInfo resolveContentProvider(String name, int flags) { + return this.mProviders.get(name); + } + + public List queryComponent(Intent intent, int type) { + + ComponentName componentName = intent.getComponent(); List resolveInfos = new ArrayList(); - ContentResolver resolver = this.mPluginContext.getContentResolver(); - for (PackageParser.Service service : this.mPackage.services) { - if (match(service, component)) { - ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.serviceInfo = service.info; - resolveInfos.add(resolveInfo); - } else if (component == null) { - // only match implicit intent - for (PackageParser.ServiceIntentInfo intentInfo : service.intents) { - if (intentInfo.match(resolver, intent, true, TAG) >= 0) { - ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.serviceInfo = service.info; - resolveInfos.add(resolveInfo); - break; - } - } + List matchComponent = getMatchComponent(componentName, type); + for (PackageParser.Component component : matchComponent) { + resolveInfos.add(getResolveInfo(component)); + } + + if (componentName == null) { + List> components = Collections.emptyList(); + if (type == TYPE_ACTIVITY) { + components = this.mPackage.activities; + } else if (type == TYPE_SERVICE) { + components = this.mPackage.services; + } else if (type == TYPE_BROADCAST_RECEIVER) { + components = this.mPackage.receivers; } + + setupImplicitIntent(intent, resolveInfos, components); } return resolveInfos; + + } - public List queryBroadcastReceivers(Intent intent, int flags) { - ComponentName component = intent.getComponent(); - List resolveInfos = new ArrayList(); - ContentResolver resolver = this.mPluginContext.getContentResolver(); + private ResolveInfo getResolveInfo(PackageParser.Component component) { + ResolveInfo resolveInfo = new ResolveInfo(); + if (component instanceof PackageParser.Activity) + resolveInfo.activityInfo = PackageParser.Activity.class.cast(component).info; + if (component instanceof PackageParser.Service) + resolveInfo.serviceInfo = PackageParser.Service.class.cast(component).info; + return resolveInfo; + } - for (PackageParser.Activity receiver : this.mPackage.receivers) { - if (receiver.getComponentName().equals(component)) { - ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.activityInfo = receiver.info; - resolveInfos.add(resolveInfo); - } else if (component == null) { - // only match implicit intent - for (PackageParser.ActivityIntentInfo intentInfo : receiver.intents) { - if (intentInfo.match(resolver, intent, true, TAG) >= 0) { - ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.activityInfo = receiver.info; - resolveInfos.add(resolveInfo); - break; - } - } + + private void initMatchMap(List packageComponents, int type) { + Map> map = null; + if (type == TYPE_ACTIVITY) { + map = mActivityMatchMap; + } else if (type == TYPE_SERVICE) { + map = mServiceMatchMap; + } else if (type == TYPE_BROADCAST_RECEIVER) { + map = mBroadcastReceiverMatchMap; + } else { + return; + } + + for (PackageParser.Component component : packageComponents) { + ComponentName componentName = component.getComponentName(); + String key = getMatchMapKey(componentName.getPackageName(), componentName.getClassName()); + addToMatchMap(map, component, key); + if (type != TYPE_BROADCAST_RECEIVER) { + key = getMatchMapKey(mHostContext.getPackageName(), componentName.getClassName()); + addToMatchMap(map, component, key); } + } + } - return resolveInfos; + private String getMatchMapKey(String pkg, String cls) { + return pkg + "/" + cls; } - public ProviderInfo resolveContentProvider(String name, int flags) { - return this.mProviders.get(name); + + private void addToMatchMap(Map> map, PackageParser.Component component, String key) { + List components; + if (map.containsKey(key)) { + components = map.get(key); + } else { + components = new ArrayList<>(); + map.put(key, components); + } + components.add(component); + } + + + private List getMatchComponent(@Nullable ComponentName componentName, int type) { + + Map> map = null; + if (type == TYPE_ACTIVITY) { + map = mActivityMatchMap; + } else if (type == TYPE_SERVICE) { + map = mServiceMatchMap; + } else if (type == TYPE_BROADCAST_RECEIVER) { + map = mBroadcastReceiverMatchMap; + } else { + return Collections.emptyList(); + } + + if (componentName == null) return Collections.emptyList(); + + String key = getMatchMapKey(componentName.getPackageName(), componentName.getClassName()); + return map.get(key); } - protected boolean match(PackageParser.Component component, ComponentName target) { - ComponentName source = component.getComponentName(); - if (source == target) return true; - if (source != null && target != null - && source.getClassName().equals(target.getClassName()) - && (source.getPackageName().equals(target.getPackageName()) - || mHostContext.getPackageName().equals(target.getPackageName()))) { - return true; + private void setupImplicitIntent(Intent intent, List resolveInfos, List> components) { + ContentResolver resolver = this.mPluginContext.getContentResolver(); + for (PackageParser.Component component : components) { + // only match implicit intent + for (PackageParser.IntentInfo intentInfo : component.intents) { + if (intentInfo.match(resolver, intent, true, TAG) >= 0) { + resolveInfos.add(getResolveInfo(component)); + break; + } + } } - return false; } /** @@ -531,7 +579,7 @@ public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotF return this.mHostPackageManager.getPackageInfo(packageName, flags); } - + @TargetApi(Build.VERSION_CODES.O) @Override public PackageInfo getPackageInfo(VersionedPackage versionedPackage, int i) throws NameNotFoundException { @@ -543,7 +591,7 @@ public PackageInfo getPackageInfo(VersionedPackage versionedPackage, int i) thro return this.mHostPackageManager.getPackageInfo(versionedPackage, i); } - + @Override public String[] currentToCanonicalPackageNames(String[] names) { return this.mHostPackageManager.currentToCanonicalPackageNames(names); @@ -579,13 +627,13 @@ public Intent getLeanbackLaunchIntentForPackage(@NonNull String packageName) { public int[] getPackageGids(@NonNull String packageName) throws NameNotFoundException { return this.mHostPackageManager.getPackageGids(packageName); } - + @TargetApi(Build.VERSION_CODES.N) @Override public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException { return this.mHostPackageManager.getPackageGids(packageName, flags); } - + @TargetApi(Build.VERSION_CODES.N) @Override public int getPackageUid(String packageName, int flags) throws NameNotFoundException { @@ -723,63 +771,63 @@ public String getNameForUid(int uid) { public List getInstalledApplications(int flags) { return this.mHostPackageManager.getInstalledApplications(flags); } - + @TargetApi(Build.VERSION_CODES.O) @Override public boolean isInstantApp() { return this.mHostPackageManager.isInstantApp(); } - + @TargetApi(Build.VERSION_CODES.O) @Override public boolean isInstantApp(String packageName) { return this.mHostPackageManager.isInstantApp(packageName); } - + @TargetApi(Build.VERSION_CODES.O) @Override public int getInstantAppCookieMaxBytes() { return this.mHostPackageManager.getInstantAppCookieMaxBytes(); } - + @TargetApi(Build.VERSION_CODES.O) @NonNull @Override public byte[] getInstantAppCookie() { return this.mHostPackageManager.getInstantAppCookie(); } - + @TargetApi(Build.VERSION_CODES.O) @Override public void clearInstantAppCookie() { this.mHostPackageManager.clearInstantAppCookie(); } - + @TargetApi(Build.VERSION_CODES.O) @Override public void updateInstantAppCookie(@Nullable byte[] cookie) { this.mHostPackageManager.updateInstantAppCookie(cookie); } - + @Override public String[] getSystemSharedLibraryNames() { return this.mHostPackageManager.getSystemSharedLibraryNames(); } - + @TargetApi(Build.VERSION_CODES.O) @NonNull @Override public List getSharedLibraries(int flags) { return this.mHostPackageManager.getSharedLibraries(flags); } - + @TargetApi(Build.VERSION_CODES.O) @Nullable @Override public ChangedPackages getChangedPackages(int sequenceNumber) { return this.mHostPackageManager.getChangedPackages(sequenceNumber); } - + @Override public FeatureInfo[] getSystemAvailableFeatures() { return this.mHostPackageManager.getSystemAvailableFeatures(); @@ -795,7 +843,7 @@ public boolean hasSystemFeature(String name) { public boolean hasSystemFeature(String name, int version) { return this.mHostPackageManager.hasSystemFeature(name, version); } - + @Override public ResolveInfo resolveActivity(Intent intent, int flags) { ResolveInfo resolveInfo = mPluginManager.resolveActivity(intent, flags); @@ -1120,8 +1168,8 @@ public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) { public Drawable getUserBadgeForDensity(UserHandle user, int density) { try { return Reflector.with(this.mHostPackageManager) - .method("getUserBadgeForDensity", UserHandle.class, int.class) - .call(user, density); + .method("getUserBadgeForDensity", UserHandle.class, int.class) + .call(user, density); } catch (Exception e) { throw new RuntimeException(e); } @@ -1288,25 +1336,26 @@ public int getApplicationEnabledSetting(String packageName) { public boolean isSafeMode() { return this.mHostPackageManager.isSafeMode(); } - + @TargetApi(Build.VERSION_CODES.O) @Override public void setApplicationCategoryHint(@NonNull String packageName, int categoryHint) { this.mHostPackageManager.setApplicationCategoryHint(packageName, categoryHint); } - + @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override - public @NonNull PackageInstaller getPackageInstaller() { + public @NonNull + PackageInstaller getPackageInstaller() { return this.mHostPackageManager.getPackageInstaller(); } - + @TargetApi(Build.VERSION_CODES.O) @Override public boolean canRequestPackageInstalls() { return this.mHostPackageManager.canRequestPackageInstalls(); } - + public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) { if (itemInfo == null) { return null;