Android P阻止调用非sdk api后,Atlas该何去何从

0、背景

    自从Android 9.0后,Android就已经开始着手阻止app开发调用非sdk的api,也就是被标记为@hide的变量、函数、类不可以通过反射调用,否则会提示NoSuchMethod异常

1、对atlas影响

   atlas有许多调用都是通过反射系统api来完成的,其中不乏被标记为@hide的类,比如用来处理插件资源的android.content.res.AssetManager#addAssetPath,还有用来处理动态部署的启动新activity的android.app.ActivityThread

    /**
     * Add an additional set of assets to the asset manager.  This can be
     * either a directory or ZIP file.  Not for use by applications.  Returns
     * the cookie of the added asset, or 0 on failure.
     * {@hide}  WARM,该方法被标记为隐藏
     */
    public final int addAssetPath(String path) {
        synchronized (this) {
            int res = addAssetPathNative(path);
            makeStringBlocks(mStringBlocks);
            return res;
        }
    }
/**
 * This manages the execution of the main thread in an
 * application process, scheduling and executing activities,
 * broadcasts, and other operations on it as the activity
 * manager requests.
 *
 * {@hide}   高能,整个类都标记为隐藏
 */
public final class ActivityThread {
如果android.content.res.AssetManager#addAssetPath不能用,资源在插件中就无法使用,如果android.app.ActivityThread整个类不让反射,那动态部署中无法添加新的activity、service

2、android p 处理非sdk调用

   但情况并没有想象的糟糕,android p 阻止调用非sdk并不是绝对的,并不是标记了hide就一定会抛异常。还有个X因素——light-greylist,如果被hide的api在里面列出,就允许被反射调用。该列表如下:

https://github.com/aosp-mirror/platform_frameworks_base/blob/master/config/hiddenapi-p-light-greylist.txt

https://github.com/aosp-mirror/platform_frameworks_base/blob/master/config/hiddenapi-light-greylist.txt

乍一看addAssetPath和ActivityThread都在里面,看来atlas还是有希望的,不过atlas用的反射有许多,让我们在Android p模拟器上运行下atlas试一试

3、死而后生,atlas的适配

  现在官网默认的master分支上的demo还没法运行,那是因为demo里反射调用了hide api且light-greylist没生命的api——android.app.ActivityThread#performRestartActivity,所以现在要运行demo请clone分支android_p

git clone https://github.com/alibaba/atlas.git -b android_p

运行后发现没有了之前的异常,但会有如下提示

05-27 04:37:31.077 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ApplicationPackageManager;->mPM:Landroid/content/pm/IPackageManager; (light greylist, reflection)
05-27 04:37:31.077 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/content/pm/ParceledListSlice;->(Ljava/util/List;)V (light greylist, linking)
05-27 04:37:31.115 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/content/pm/PackageParser;->()V (light greylist, reflection)
05-27 04:37:31.115 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/content/res/StringBlock;->(JZ)V (light greylist, reflection)
05-27 04:37:31.115 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ActivityThread;->mInstrumentation:Landroid/app/Instrumentation; (light greylist, reflection)
05-27 04:37:31.115 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ActivityThread;->mAllApplications:Ljava/util/ArrayList; (light greylist, reflection)
05-27 04:37:31.115 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ActivityThread;->mInitialApplication:Landroid/app/Application; (light greylist, reflection)
05-27 04:37:31.115 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap; (light greylist, reflection)
05-27 04:37:31.115 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ActivityThread;->sPackageManager:Landroid/content/pm/IPackageManager; (light greylist, reflection)
05-27 04:37:31.116 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/LoadedApk;->mApplication:Landroid/app/Application; (light greylist, reflection)
05-27 04:37:31.116 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/LoadedApk;->mResources:Landroid/content/res/Resources; (light greylist, reflection)
05-27 04:37:31.116 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/LoadedApk;->mResDir:Ljava/lang/String; (light greylist, reflection)
05-27 04:37:31.116 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/LoadedApk;->mClassLoader:Ljava/lang/ClassLoader; (light greylist, reflection)
05-27 04:37:31.116 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/LoadedApk;->mBaseClassLoader:Ljava/lang/ClassLoader; (light greylist, reflection)
05-27 04:37:31.116 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/LoadedApk;->mAppDir:Ljava/lang/String; (light greylist, reflection)
05-27 04:37:31.116 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ContextImpl;->mResources:Landroid/content/res/Resources; (light greylist, reflection)
05-27 04:37:31.117 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ContextImpl;->mTheme:Landroid/content/res/Resources$Theme; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/view/ContextThemeWrapper;->mTheme:Landroid/content/res/Resources$Theme; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/view/ContextThemeWrapper;->mResources:Landroid/content/res/Resources; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/ContextWrapper;->mBase:Landroid/content/Context; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$Component;->intents:Ljava/util/ArrayList; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$Package;->activities:Ljava/util/ArrayList; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$Package;->services:Ljava/util/ArrayList; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$Package;->receivers:Ljava/util/ArrayList; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$Package;->providers:Ljava/util/ArrayList; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$Package;->applicationInfo:Landroid/content/pm/ApplicationInfo; (light greylist, reflection)
05-27 04:37:31.118 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$Package;->packageName:Ljava/lang/String; (light greylist, reflection)
05-27 04:37:31.119 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$ActivityIntentInfo;->activity:Landroid/content/pm/PackageParser$Activity; (light greylist, reflection)
05-27 04:37:31.119 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/pm/PackageParser$Service; (light greylist, reflection)
05-27 04:37:31.119 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$ProviderIntentInfo;->provider:Landroid/content/pm/PackageParser$Provider; (light greylist, reflection)
05-27 04:37:31.119 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/content/pm/PackageParser$Provider;->info:Landroid/content/pm/ProviderInfo; (light greylist, reflection)
05-27 04:37:31.119 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ActivityManager;->IActivityManagerSingleton:Landroid/util/Singleton; (light greylist, reflection)
05-27 04:37:31.119 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/util/Singleton;->mInstance:Ljava/lang/Object; (light greylist, reflection)
05-27 04:37:31.120 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ActivityThread$AppBindData;->providers:Ljava/util/List; (light greylist, reflection)
05-27 04:37:31.120 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ActivityThread;->mBoundApplication:Landroid/app/ActivityThread$AppBindData; (light greylist, reflection)
05-27 04:37:31.120 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden field Landroid/app/ContextImpl;->mPackageInfo:Landroid/app/LoadedApk; (light greylist, reflection)
05-27 04:37:31.121 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/app/ActivityThread;->currentActivityThread()Landroid/app/ActivityThread; (light greylist, reflection)
05-27 04:37:31.121 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/content/res/AssetManager;->addAssetPath(Ljava/lang/String;)I (light greylist, reflection)
05-27 04:37:31.121 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/content/res/AssetManager;->addAssetPathAsSharedLibrary(Ljava/lang/String;)I (light greylist, reflection)
05-27 04:37:31.121 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/app/Application;->attach(Landroid/content/Context;)V (light greylist, reflection)
05-27 04:37:31.121 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/content/pm/PackageParser$Component;->getComponentName()Landroid/content/ComponentName; (light greylist, reflection)
05-27 04:37:31.121 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/app/ContextImpl;->setOuterContext(Landroid/content/Context;)V (light greylist, reflection)
05-27 04:37:31.122 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/content/res/AssetManager;->getResourceIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I (light greylist, reflection)
05-27 04:37:31.122 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/app/ActivityThread;->installContentProviders(Landroid/content/Context;Ljava/util/List;)V (light greylist, reflection)
05-27 04:37:31.122 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/app/ActivityThread;->installProvider(Landroid/content/Context;Landroid/app/ContentProviderHolder;Landroid/content/pm/ProviderInfo;ZZZ)Landroid/app/ContentProviderHolder; (light greylist, reflection)
05-27 04:37:31.122 2972-2972/com.taobao.demo W/com.taobao.dem: Accessing hidden method Landroid/app/Service;->attach(Landroid/content/Context;Landroid/app/ActivityThread;Ljava/lang/String;Landroid/os/IBinder;Landroid/app/Application;Ljava/lang/Object;)V (light greylist, reflection)

hide api在light greylist中,调用时都会有警告,但还好大部分都可以被反射调用了

当然也有失败的情况:

0 = {Hack$HackDeclaration$HackAssertionException@5211} "android.taobao.atlas.hack.Hack$HackDeclaration$HackAssertionException: java.lang.NoSuchFieldException: No field mStringBlocks in class Landroid/content/res/AssetManager; (declaration of 'android.content.res.AssetManager' appears in /system/framework/framework.jar)"
1 = {Hack$HackDeclaration$HackAssertionException@5212} "android.taobao.atlas.hack.Hack$HackDeclaration$HackAssertionException: java.lang.NoSuchMethodException: ensureStringBlocks []"
2 = {Hack$HackDeclaration$HackAssertionException@5213} "android.taobao.atlas.hack.Hack$HackDeclaration$HackAssertionException: java.lang.NoSuchMethodException: addAssetPathNative [class java.lang.String]"
3 = {Hack$HackDeclaration$HackAssertionException@5214} "android.taobao.atlas.hack.Hack$HackDeclaration$HackAssertionException: java.lang.NoSuchMethodException: addAssetPathNative [class java.lang.String, boolean]"
4 = {Hack$HackDeclaration$HackAssertionException@5215} "android.taobao.atlas.hack.Hack$HackDeclaration$HackAssertionException: java.lang.NoSuchMethodException: addAssetPathNative [class java.lang.String, int]"
5 = {Hack$HackDeclaration$HackAssertionException@5216} "android.taobao.atlas.hack.Hack$HackDeclaration$HackAssertionException: java.lang.NoSuchMethodException: getStringBlockCount []"
6 = {Hack$HackDeclaration$HackAssertionException@5217} "android.taobao.atlas.hack.Hack$HackDeclaration$HackAssertionException: java.lang.NoSuchMethodException: getNativeStringBlock [int]"

不过这些都是一些兼容性处理的反射调用,不会影响到整个atlas的框架。

所以从目前来看atlas在Android不会因为hide  api限制而作废

4、hide api 自相矛盾的现状

   为什么Android会开放出light greylist来运行反射调用hide api呢?为什么没法立即执行这个限制呢?

   原因很可能还是Android studio中需要使用,Instant Run是主要使用者,而Instant Run这种机制还主要是用的插件化的思想来完成的(不清楚的自行百度instant run原理),atlas中调用的大部分还是Instant Run需要用的,如果Android一刀切,可能自己的工具也会遭殃,所以这个是Android hide api中矛盾的现状。

5、未来,未知...

   如果Android未来删除了light greylist、如果Android p正式版的限制更加严格、甚至Android更改了activity的启动源码,这都不好说,有许多未知问题,不过这不是因为Android自身问题,而是这些api本身就是隐藏的。但是,插件话加载的核心还是DexClassLoader的使用。

6、未来,猜测

   就算Android屏蔽了所有的hide api,只要DexClassLoader可以使用,我们还是可以实现插件化开发,以后减少对Android系统组件依赖,使用weex、rn解耦可能是趋势,而阿里巴巴现在本身一直都在推广weex,集团下app大都也是插件化和weex并用,所以我们就等待安心等待Android p的到来、未来的到来。


你可能感兴趣的:(android)