您的位置:首页 > 移动开发 > Android开发

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

2018-02-05 08:39 260 查看
最近在研究安Android 源码的时候偶然发现,在framework中有一个如下的提交,让人感觉比较有意思

字面意思比较直接:不让或者限制使用非公开的api方法(也就算@hide 注塑的public方法).根据这个提交,顺带研究了下大部分提交。原理,水平有限没太看懂。

commit 927d6de11fa038ee78bb90933eee3ebc20b68751
Author: David Brazdil <dbrazdil@google.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开发也算是指明了个大体的方向把。

建议:

ODM、Android设备厂商禁止使用make update-api 这种方式来动态的增加暴露给外部的api函数。所有framework新增的public方法一律添加@hide注释。

后续可能存在的风险,例如无法测试通过cts

无法正常升级等等

规范使用android 所提供的接口信息。让你做什么你就做什么

反射、等通过各种技术手段所绕过的独立的app,要注意了。

个人猜测目前你应该是有大量的应用直接或者间接的使用了个字hide方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: