Android 使用隐藏api所可能带来的隐患

最近在研究安Android 源码的时候偶然发现,在framework中有一个如下的提交,让人感觉比较有意思
字面意思比较直接:不让或者限制使用非公开的api方法(也就算@hide 注塑的public方法).根据这个提交,顺带研究了下大部分提交。原理,水平有限没太看懂。

commit 927d6de11fa038ee78bb90933eee3ebc20b68751
Author: David Brazdil .com>
Date:   Wed Jan 24 19:54:30 2018 +0000

    Show a warning toast/dialog when an app uses hidden APIs

    Check VMRuntime.hasUsedHiddenApi() on each Activity start and show
    a toast/dialog urging the user to check logcat.

    Test: manual
    Bug: 64382372
    Change-Id: Ida8a6ed9ab9b56a76882501b2a3473a5f1448cb3

diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index dbdb81c..2e7a0ed 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -128,6 +128,8 @@ import com.android.internal.app.WindowDecorActionBar;
 import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;

+import dalvik.system.VMRuntime;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -7039,11 +7041,12 @@ public class Activity extends ContextThemeWrapper
         mFragments.dispatchStart();
         mFragments.reportLoaderStart();

-        // This property is set for all builds except final release
-        boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;
         boolean isAppDebuggable =
                 (mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;

+        // This property is set for all builds except final release
+        boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;
+
         if (isAppDebuggable || isDlwarningEnabled) {
             String dlwarning = getDlWarning();
             if (dlwarning != null) {
@@ -7064,6 +7067,28 @@ public class Activity extends ContextThemeWrapper
             }
         }

+        // We might disable this for final builds.
+        boolean isApiWarningEnabled = true;
+
+        if (isAppDebuggable || isApiWarningEnabled) {
+            if (VMRuntime.getRuntime().hasUsedHiddenApi()) {
+                String appName = getApplicationInfo().loadLabel(getPackageManager())
+                        .toString();
+                String warning = "Detected problems with API compatiblity\n"
+                                 + "(please consult log for detail)";
+                if (isAppDebuggable) {
+                    new AlertDialog.Builder(this)
+                        .setTitle(appName)
+                        .setMessage(warning)
+                        .setPositiveButton(android.R.string.ok, null)
+                        .setCancelable(false)
+                        .show();
+                } else {
+                    Toast.makeText(this, appName + "\n" + warning, Toast.LENGTH_LONG).show();
+                }
+            }
+        }
+
         mActivityTransitionState.enterReady(this);
     }

以下的跟人见解是基于初步研读了当前(截止2018/02/03)的关于限制使用hide api的方案之后的。不一定正确,

基于源码环境编译的app

这种也就是我们俗称的手机厂商、ODM厂商通常会遇到的情况
是如何限制使用hide api的?
对此专门开发了一个名为hiddenapi的工具,在并且在编译生成odex文件的时候,会去check是否有使用你hide 标注的public方法。
如何绕过该限制呢?
初步看应该是可以通过config文件类进行配置,类似private-runtime-permission.xml这种
配置文件的路径:framework/base/config/, 可以看到hiddenapi-blacklist.txt hiddenapi-dark-greylist.txt两个文件。
对应的代码提交

define hiddenapi-copy-dex-files
$(2): $(1) $(HIDDENAPI) $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
      $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
    @rm -rf $(dir $(2))
    @mkdir -p $(dir $(2))
    find $(dir $(1)) -maxdepth 1 -name "classes*.dex" | sort | \
        xargs -I{} cp -f {} $(dir $(2))
    find $(dir $(2)) -name "classes*.dex" | sort | sed 's/^/--dex=/' | \
        xargs $(HIDDENAPI) --light-greylist=$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
                           --dark-greylist=$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) \
                           --blacklist=$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
endef

define hiddenapi-copy-soong-jar
$(2): PRIVATE_FOLDER := $(dir $(2))dex-hiddenapi
$(2): $(1) $(HIDDENAPI) $(SOONG_ZIP) $(MERGE_ZIPS) $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
      $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
    @echo "Hidden API: $$@"
	$$(copy-file-to-target)
    @rm -rf $${PRIVATE_FOLDER}
	@mkdir -p $${PRIVATE_FOLDER}
    unzip -q $(2) 'classes*.dex' -d $${PRIVATE_FOLDER}
    find $${PRIVATE_FOLDER} -name "classes*.dex" | sort | sed 's/^/--dex=/' | \
		xargs $(HIDDENAPI) --light-greylist=$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
		                   --dark-greylist=$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) \
		                   --blacklist=$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
	$(SOONG_ZIP) -o $${PRIVATE_FOLDER}/classes.dex.jar -C $${PRIVATE_FOLDER} -D $${PRIVATE_FOLDER}
    $(MERGE_ZIPS) -D -zipToNotStrip $${PRIVATE_FOLDER}/classes.dex.jar -stripFile "classes*.dex" \
        $(2) $${PRIVATE_FOLDER}/classes.dex.jar $(1)
endef

framework层提示使用了隐藏的api的控制属性

# -----------------------------------------------------------------
# Enable dynamic linker and hidden API developer warnings for
# userdebug, eng and non-REL builds
ifneq ($(TARGET_BUILD_VARIANT),user)
                                 ro.art.hiddenapi.warning=1
else
# Enable it for user builds as long as they are not final.
ifneq ($(PLATFORM_VERSION_CODENAME),REL)
                                 ro.art.hiddenapi.warning=1
endif
endif

上传两张相关的代码片段

这里写图片描述
这里写图片描述

基于Google release的SDK所编写的app

者在也就所我们通常在各个应用市场上所下载的app.
通过上一步的分析,可以看出,其实在install独立的应用时,也是会check是否使用了非公开的api的;这对于后续的app开发也算是指明了个大体的方向把。

建议:

  1. ODM、Android设备厂商禁止使用make update-api 这种方式来动态的增加暴露给外部的api函数。所有framework新增的public方法一律添加@hide注释。
    1. 后续可能存在的风险,例如无法测试通过cts
    2. 无法正常升级等等
  2. 规范使用android 所提供的接口信息。让你做什么你就做什么
  3. 反射、等通过各种技术手段所绕过的独立的app,要注意了。
  4. 个人猜测目前你应该是有大量的应用直接或者间接的使用了个字hide方法

你可能感兴趣的:(Android)