訪問framework中hide方法

瓜的呱發表於2024-05-08

經常大家會做安卓系統開發工作問到一個問題,那就是我如果framework程式碼中增加了一個方法啥的,但是我又不想公開給第三方應用知道,只想讓我係統的應用知道,那該怎麼辦呢?其實這個時候經常就會用到一個hidden的標籤,來代表這個方法是隱藏方法,隱藏方法就是給系統內部用的,意味著第三方app就無法使用。這個其實也很常見,自從android p開始android系統就開始對訪問hidden的限制越來越嚴格,雖然我們網路上有各種奇葩招來逃避不允許呼叫hidden api,這個第三方應用奇葩方法呼叫hidden不是我們重點。

我們重點當然是我們做android系統的,我們系統原始碼都可以隨意改,根本不需要那種第三方應用使用的奇葩方法來逃避hidden api(畢竟這個屬於野路子,google可能下一個版本就改變了,野路子無效了),所以該方案僅僅適用於你可以修改原始碼情況下,可以對第三方應用,系統應用都可以訪問hidden api

1、看看系統中介面是怎麼定義成了hidden如下:

我們以ActivityManager的類為例子
frameworks/base/core/java/android/app/ActivityManager.java

    /** @hide */   這裡的 
    public static int checkUidPermission(String permission, int uid) {
        try {
            return AppGlobals.getPackageManager()
                    .checkUidPermission(permission, uid);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
/** @hide */ 這個標籤最為關鍵,表示這個方法是個隱藏方法不會出現在sdk中,也不會出現編譯報錯要make update-api

2、那麼系統應用app怎麼訪問這個framework的hidden介面呢?

其實這個hidden介面訪問有2中方式

1、反射方法,這種最簡單直接呼叫地方寫成反射就可以,但是程式碼可讀性差一點

                    ClassLoader loader = MainActivity.this.getClassLoader();//得到當前類的classLoader
                    Class<?> clz;

                    clz = Class.forName("android.app.ActivityManager"); //載入類
                   @SuppressLint("SoonBlockedPrivateApi") Method m = clz.getDeclaredMethod("checkUidPermission", String.class, int.class); //獲取方法


                    int permisson = (Integer) m.invoke(clz, "android.permission.INJECT_EVENTS",1000);  //反射呼叫,static方法呼叫時,不必得到物件示例

2、製作一個包裝介面jar包,jar是有系統原始碼編譯的,可以訪問hidden介面,具體如下:

package com.android.third.call;

import android.app.ActivityManager;

public class ThirdInterface {
    public ThirdInterface() {
    }

    public static int callHiddenFun() {
        return ActivityManager.checkUidPermission("android.permission.INJECT_EVENTS", 1000);
    }
}
注意哦,這裡我們需要android原始碼環境編譯哦,編譯成一個jar,對應的mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := thirdinterface
LOCAL_MODULE_STEM := thirdinterface
LOCAL_DEX_PREOPT := false
include $(BUILD_STATIC_JAVA_LIBRARY)

然後 :make thirdinterface 就可以獲取對應的jar包

然後需要使用這個jar包的app進行複製這個javalib.jar到工程中的lib路徑

匯入後就可以原始碼中呼叫了

3、呼叫成功就能執行成功麼?

這個其實在以前android還沒有對hidden api的執行做限制時候,確實呼叫編譯透過了就代表執行也也可以成功,但是從android 9以後,發現呼叫都會出現以下錯誤logcat列印:
2021-11-28 08:23:55.695 26050-26050/com.example.anrdemo W/example.anrdem: Accessing hidden method Landroid/app/ActivityManager;->checkUidPermission(Ljava/lang/String;I)I (greylist-max-o, linking, denied)

如果看到了Accessing hidden method ,那基本就是代表你其實一切都ok,就是被系統攔截不讓你呼叫了,這裡就不用懷疑什麼方法寫錯了,反射寫錯了,如果沒有這個列印要麼你就執行成功,要麼就是方法寫錯

4、系統解決hidden api呼叫

那麼系統層面桌面解決讓訪問呼叫的hidden api呢?這個其實我們系統層面早就考慮到了需要給一些應用讓其可以訪問hidden,具體程式碼可以看這裡:
base/core/java/android/content/pm/ApplicationInfo.java

這裡其實就有一個isAllowedToUseHiddenApis方法,這個非常關鍵,分別對程式碼進行註釋講解:

    private boolean isAllowedToUseHiddenApis() {
        if (isSignedWithPlatformKey()) { //如果app platform簽名直接就可以呼叫hidden api
            return true;
        } else if (isSystemApp() || isUpdatedSystemApp()) { //如果沒有platform簽名,但是屬於system/app,那麼就會根據白名單進行過濾是否可以
            return usesNonSdkApi() || isPackageWhitelistedForHiddenApis();
        } else {
            //return false;原來第三方是直接返回false
           return isPackageWhitelistedForHiddenApis();
           //這裡改成第三方應用也可以根據這個白名單來
        }
    }

那麼這個白名單在哪呢?
原始碼在
~/xiaomi5/frameworks/base/data/etc/hiddenapi-package-whitelist.xml
手機上在:
/system/etc/sysconfig/

看目前內容:

<?xml version="1.0" encoding="utf-8"?>

<config>
  <hidden-api-whitelisted-app package="com.example.anrdemo" /> <!--這裡就是我們增加的第三方應用package Name-->
  <hidden-api-whitelisted-app package="android.ext.services" />
  <hidden-api-whitelisted-app package="com.android.apps.tag" />
  <hidden-api-whitelisted-app package="com.android.basicsmsreceiver" />
  <hidden-api-whitelisted-app package="com.android.bookmarkprovider" />
  <hidden-api-whitelisted-app package="com.android.calllogbackup" />
  <hidden-api-whitelisted-app package="com.android.camera" />
  <hidden-api-whitelisted-app package="com.android.car.dialer" />
  <hidden-api-whitelisted-app package="com.android.car.messenger" />
  <hidden-api-whitelisted-app package="com.android.car.overview" />
  <hidden-api-whitelisted-app package="com.android.car.stream" />
  <hidden-api-whitelisted-app package="com.android.companiondevicemanager" />
  <hidden-api-whitelisted-app package="com.android.dreams.basic" />
  <hidden-api-whitelisted-app package="com.android.gallery" />
  <hidden-api-whitelisted-app package="com.android.launcher3" />
  <hidden-api-whitelisted-app package="com.android.mtp" />
  <hidden-api-whitelisted-app package="com.android.musicfx" />
  <hidden-api-whitelisted-app package="com.android.permissioncontroller" />
  <hidden-api-whitelisted-app package="com.android.printservice.recommendation" />
  <hidden-api-whitelisted-app package="com.android.printspooler" />
  <hidden-api-whitelisted-app package="com.android.providers.blockednumber" />
  <hidden-api-whitelisted-app package="com.android.providers.calendar" />
  <hidden-api-whitelisted-app package="com.android.providers.contacts" />
  <hidden-api-whitelisted-app package="com.android.providers.downloads" />
  <hidden-api-whitelisted-app package="com.android.providers.downloads.ui" />
  <hidden-api-whitelisted-app package="com.android.providers.media" />
  <hidden-api-whitelisted-app package="com.android.providers.tv" />
  <hidden-api-whitelisted-app package="com.android.providers.userdictionary" />
  <hidden-api-whitelisted-app package="com.android.smspush" />
  <hidden-api-whitelisted-app package="com.android.spare_parts" />
  <hidden-api-whitelisted-app package="com.android.statementservice" />
  <hidden-api-whitelisted-app package="com.android.storagemanager" />
  <hidden-api-whitelisted-app package="com.android.systemui.plugins" />
  <hidden-api-whitelisted-app package="com.android.terminal" />
  <hidden-api-whitelisted-app package="com.android.wallpaper" />
  <hidden-api-whitelisted-app package="jp.co.omronsoft.openwnn" />
</config>

其實很容易看懂,這下面的名單都可以進行hidden api,我們要增加啥應用只需要加上包名如:

當然這裡如果android原生只支援system app,大家有疑問system app難道不應該是platform簽名麼?那麼簽名不就直接返回麼?其實還真的不是,其實很多系統應用也不一定系統簽名哈,有media,啥的簽名故就靠這個白名單了。
我們前面對ApplicationInfo進行了修改就可以進行第三方應用包名也寫入了。
然後進行編譯後,我們第三方應用就可以正常執行hidden api透過了:


相關文章