Android 必知必會 - 獲取手機系統的構建模式

如果移動端訪問不佳,請使用 => GitHub 版

關鍵詞:Android 、Make 、user mode 、user 、userdebug 、eng


判定手機系統的構建模式、用戶模式

編譯 Rom 時,需要指定目標構建模式,構建模式有三種:用戶模式 user、用戶調試模式 userdebug 和工程模式 eng

  • 用戶模式 user 
    • 僅安裝標籤爲 user 的模塊
    • 設定屬性 ro.secure=1,打開安全檢查功能
    • 設定屬性 ro.debuggable=0,關閉應用調試功能
    • 默認關閉 adb 功能
    • 打開 Proguard 混淆器
    • 打開 DEXPREOPT 預先編譯優化
  • 用戶調試模式 userdebug 
    • 安裝標籤爲 user、debug 的模塊
    • 設定屬性 ro.secure=1,打開安全檢查功能
    • 設定屬性 ro.debuggable=1,啓用應用調試功能
    • 默認打開 adb 功能
    • 打開 Proguard 混淆器
    • 打開 DEXPREOPT 預先編譯優化
  • 工程模式 eng 
    • 安裝標籤爲 user、debug、eng 的模塊
    • 設定屬性 ro.secure=0,關閉安全檢查功能
    • 設定屬性 ro.debuggable=1,啓用應用調試功能
    • 設定屬性 ro.kernel.android.checkjni=1,啓用 JNI 調用檢查
    • 默認打開 adb 功能
    • 關閉 Proguard 混淆器
    • 關閉 DEXPREOPT 預先編譯優化

指定目標構建模式:在 make 命令中加入參數

$ sudo make -j8 PRODUCT-rk312x-user
$ sudo make -j8 PRODUCT-rk312x-userdebug
$ sudo make -j8 PRODUCT-rk312x-eng
  • 1
  • 2
  • 3

來源:https://www.kancloud.cn/amoy0226/fireprime_android_compile/105885

判斷構建模式

思路:通過觀察以上三個模式的屬性,這裏使用安全檢查功能(ro.securero)和應用調試功能(ro.debuggable)兩個屬性來區分這三個模式:

  • user: 
    • ro.securero = 1
    • ro.debuggable = 0
  • userdebug 
    • ro.securero = 1
    • ro.debuggable = 1
  • eng 
    • ro.securero = 0
    • ro.debuggable = 1

其中,如果只需判斷是否爲 user 模式,使用 ro.debuggable 一個屬性即可。

尋找源碼

在 android.os.Build 的源碼中我發現一個靜態變量:

/**
 * Returns true if we are running a debug build such as "user-debug" or "eng".
 * @hide
 */
public static final boolean IS_DEBUGGABLE =
    SystemProperties.getInt("ro.debuggable", 0) == 1;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

但是沒有 ro.securero 這個屬性,進一步發現其調用的是 android.os.SystemProperties 的 getInt() 函數,那可以直接使用它來獲取ro.securero 的值。

由於是 android.os.SystemProperties 是隱藏類,我們可以使用兩種方式來調用其方法:

方法一:使用修改過增加了這些隱藏類的 android.jar 來編譯 APK,此方式問題較多,配置繁瑣,不推薦;

方法二:使用反射調用,普通 App 即可使用,無限制,推薦使用此方法。

代碼實現

先說下方法一下的實現:

/**
 * 獲取系統構建模式
 *
 * @return int(0:未知, 1 user, 2 userdebug, 3 eng)
 */
public static int getOSMode() {
    int debug = SystemProperties.getInt("ro.debuggable", -1);
    int secure = SystemProperties.getInt("ro.secure", -1);

    if (debug == 0 && secure == 1) return 1;
    else if (debug == 1 && secure == 1) return 2;
    else if (debug == 1 && secure == 0) return 3;
    else return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

那麼方法二隻是和方法一的屬性獲取方式不一樣:

/**
 * 獲取系統構建模式
 *
 * @return int(0:未知, 1 user, 2 userdebug, 3 eng)
 */
public static int getOSMode() {
    try {
        Class clazz = Class.forName("android.os.SystemProperties");
        int debug = (int) clazz.getMethod("getInt", String.class, int.class).invoke(clazz, "ro.debuggable", -1);
        int secure = (int) clazz.getMethod("getInt", String.class, int.class).invoke(clazz, "ro.secure", -1);
        if (debug == 0 && secure == 1) return 1;
        else if (debug == 1 && secure == 1) return 2;
        else if (debug == 1 && secure == 0) return 3;
        else return 0;
    } catch (ClassNotFoundException ignore) {
    } catch (NoSuchMethodException ignore) {
    } catch (IllegalAccessException ignore) {
    } catch (InvocationTargetException ignore) {
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

這裏未對反射時可能產生的異常做處理,只是簡單的返回 0,有需要請自行處理。

總結

android.os.Build 和 android.os.SystemProperties 的源碼在 Android SDK 中,很方便尋找,比較困難的一步就是了解到所需的屬性和這兩個類有關,這就需要對 Android Rom 的編譯有一點了解。

PS:如果有什麼建議或者問題,可以通過下面的方式和我聯繫

閒聊羣 : 668524118
本羣主要用於編程技術 ,及創意作品 ,思維架構的交流 ,歡迎喜歡創新 ,熱愛生活的朋友加入 !

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章