Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 第九章:Android系統信息與安全機制

第九章:Android系統信息與安全機制

編輯:關於Android編程

知識點目錄

9.1 Android系統信息獲取
9.1.1 android.os.Build 9.1.2 SystemProperty 9.1.3 Android系統信息實例 9.2 Android Apk應用信息獲取之PackageManager
9.2.1 PackageManager 9.3 Android Apk應用信息獲取之ActivityManager 9.4 解析Packages.xml獲取系統信息 9.5 Android安全機制
9.5.1 Android安全機制簡介 9.5.2 Android系統安全隱患 9.5.3 Android Apk反編譯 9.5.4 Android Apk加密

知識點回顧

9.1 Android系統信息獲取

要獲取系統的配置信息,通常可以從以下兩個方面獲取:

android.os.Build SystemProperty

9.1.1 android.os.Build

該類包含系統編譯時大量設備、配置信息:

Build.BOARD:主板 Build.BRAND:Android系統定制商 Build.SUPPORTED_ABIS:CPU指令集 Build.DEVICE:設備參數 Build.DISPLAY:顯示屏參數 Build.FINGERPRINT:唯一編號 Build.SERIAL:硬件序列號 Build.ID:修訂版本列表 Build.MANUFACTURER:硬件制造商 Build.MODEL:版本 Build.HARDWARE:硬件名 Build.PRODUCT:手機產品名 Build.TAGS:描述Build的標簽 Build.TYPE:Builder類型 Build.VERSION.CODENAME:當前開發代號 Build.VERSION.INCREMENTAL:源碼控制版本號 Build.VERSION.RELEASE:版本字符串 Build.VERSION.SDK_INT:版本號 Build.HOST:host值 Build.USER:User名 Build.TIME:編譯時間

9.1.2 SystemProperty

SystemProperty包含了許多系統配置屬性值和參數:

os.version:OS版本 os.name:OS名稱 os.arch:OS架構 user.home:Home屬性 user.name:Name屬性 user.dir:Dir屬性 user.timezone:時區 path.separator:路徑分隔符 line.separator:行分隔符 file.separator:文件分隔符 java.vendor.url:Java vender Url屬性 java.class.path:Java Class屬性 java.class.version:Java Class版本 java.vendor:Java Vender屬性 java.version:Java版本 java.home:Java Home屬性

9.1.3 Android系統信息實例

上面列舉了那麼多,讓我們通過代碼獲取他們的系統信息:

String board = Build.BOARD;
String brand = Build.BRAND;

String os_version = System.getProperty("os.version");
String os_name = System.getProperty("os.name");

我們還可以通過命令行模式查看系統信息:

命令行模式進入system/build.prop文件目錄,使用cat build.prop命令查看文件信息

我們還可以通過adb shell的getprop來獲取對應的屬性值:

進入adb shell,使用getprop ro.build.id獲取信息

還有一個非常重要的目錄存儲系統信息,那就是/proc目錄:

命令行模式進入/proc文件目錄,使用cat cpuinfo命令打開cpuinfo文件查看系統信息

9.2 Android Apk應用信息獲取之PackageManager

看了這麼多系統信息,應該看Apk應用信息了,在ADB Shell命令中,有兩個非常強大的助手,PM和AM,PM主宰著應用的包管理,而AM主宰著應用的活動管理

9.2.1 PackageManager

ActivityInfo
ActivityInfo封裝在了Mainfest文件中的< activity >和< eceiver>之間的所有信息,包括name、icon、label、launchMode等。 ServiceInfo
ServiceInfo與ActivityInfo類似,封裝了< service>之間的所有信息。 ApplicationInfo
它封裝了< application>之間的信息,特別的是,ApplicationInfo包含了很多Flag
FLAG_SYSTEM表示為系統應用 FLAG_EXTERNAL_STORAGE表示為安裝在SDcard上的應用 PackageInfo
PackageInfo與前面三個Info類類似,都是用於封裝Manifest文件的相關節點信息,而PageageInfo包含了所有的Activity和Service信息。 ResolveInfo
ResolveInfo包含了< intent>信息的上一級信息,所以它可以返回ActivityInfo、ServiceInfo等包含了< intent>的信息 PackageManager中封裝的用來獲取這些信息的方法:
getPackageManager():通過這個方法可以返回一個PackageManager對象 getApplicationInfo():以ApplicationInfo的形式返回指定包名的ApplicationInfo getApplicationIcon():返回指定包名的Icon getInstalledApplications():以ApplicationInfo的形式返回安裝的應用 getInstalledPackages():以PackageInfo的形式返回安裝的應用 queryIntentActivities():返回指定Intent的ResolveInfo對象、Activity集合 queryIntentServices():返回指定Intent的ResolveInfo對象、Service集合 resolveActivity():返回指定Intent的Activity resolveService():返回指定Intent的Service

下面通過一個實際的例子通過PackageManager篩選不同類型的App,利用ApplicationInfo中的FLAG_SYSTEM來判斷:

app.flags & ApplicationInfo.FLAG_SYSTEM
如果當前應用的flags & ApplicationInfo.FLAG_SYSTEM != 0則為系統應用 如果flags & ApplicationInfo.FLAG_SYSTEM <= 0 則為第三方應用 特殊的,當系統應用升級後,也將會成為第三方應用: flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0 如果當前應用的flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE != 0 則為安裝在SDCard上的應用

我們封裝一個Bean來保存我們所需的字段:

public class PMAppInfo {

    private String appLabel;
    private Drawable appIcon;
    private String pkgName;

    public PMAPPInfo(){
    }

    public String getAppLabel() {
        return appLabel;
    }

    public void setAppLabel(String appLabel) {
        this.appLabel = appLabel;
    }

    public Drawable getAppIcon() {
        return appIcon;
    }

    public void setAppIcon(Drawable appIcon) {
        this.appIcon = appIcon;
    }

    public String getPkgName() {
        return pkgName;
    }

    public void setPkgName(String pkgName) {
        this.pkgName = pkgName;
    }
}

接下來,通過上面所說的判斷方法來判斷各種類型的應用:

private List getAppInfo(int flag) {
    // 獲取PackageManager對象
    pm = this.getPackageManager();
    // 獲取應用信息
    List listAppcations = pm
            .getInstalledApplications(
                    PackageManager.GET_UNINSTALLED_PACKAGES);
    List appInfos = new ArrayList();
    // 判斷應用類型
    switch (flag) {
        case ALL_APP:
            appInfos.clear();
            for (ApplicationInfo app : listAppcations) {
                appInfos.add(makeAppInfo(app));
            }
            break;
        case SYSTEM_APP:
            appInfos.clear();
            for (ApplicationInfo app : listAppcations) {
                if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                    appInfos.add(makeAppInfo(app));
                }
            }
            break;
        case THIRD_APP:
            appInfos.clear();
            for (ApplicationInfo app : listAppcations) {
                if ((app.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
                    appInfos.add(makeAppInfo(app));
                } else if ((app.flags &
                        ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
                    appInfos.add(makeAppInfo(app));
                }
            }
            break;
        case SDCARD_APP:
            appInfos.clear();
            for (ApplicationInfo app : listAppcations) {
                if ((app.flags &
                        ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
                    appInfos.add(makeAppInfo(app));
                }
            }
            break;
        default:
            return null;
    }
    return appInfos;
}

private PMAppInfo makeAppInfo(ApplicationInfo app) {
    PMAppInfo appInfo = new PMAppInfo();
    appInfo.setAppLabel((String) app.loadLabel(pm));
    appInfo.setAppIcon(app.loadIcon(pm));
    appInfo.setPkgName(app.packageName);
    return appInfo;
}

效果圖

\

9.3 Android Apk應用信息獲取之ActivityManager

ActivityManager獲取應用程序信息封裝了不少Bean對象:

ActivityManager.MemoryInfo
MemoryInfo有幾個非常重要的字段:availMem(系統可用內存),totalMem(總內存),threshold(低內存的阈值,即區分是否低內存的臨界值),lowMemory(是否處於低內存) Debug.MemoryInfo
這個MemoryInfo用於統計進程下的內存信息 RunningAppProcessInfo
運行進程的信息,存儲的字段有:processName(進程名),pid(進程pid),uid(進程uid),pkgList(該進程下的所有包) RunningServiceInfo
運行的服務信息,在它裡面同樣包含了一些服務進程信息,同時還有一些其他信息,activeSince(第一次被激活的時間、方式),foreground(服務是否在後台執行)

下面同樣通過例子來看看如何使用ActivityManager,我們封裝一個Bean來保存我們所需的字段:

public class AMProcessInfo {

    private String pid;
    private String uid;
    private String memorySize;
    private String processName;

    public AMProcessInfo() {
    }

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getMemorySize() {
        return memorySize;
    }

    public void setMemorySize(String memorySize) {
        this.memorySize = memorySize;
    }

    public String getProcessName() {
        return processName;
    }

    public void setProcessName(String processName) {
        this.processName = processName;
    }
}

接下來,調用getRunningAppProcesses方法,返回當前運行的進程信息,並將我們關心的信息保存到Bean中:

private List getRunningProcessInfo() {
        mAmProcessInfoList = new ArrayList();

        List appProcessList =
                mActivityManager.getRunningAppProcesses();

        for (int i = 0; i < appProcessList.size(); i++) {
            ActivityManager.RunningAppProcessInfo info =
                    appProcessList.get(i);
            int pid = info.pid;
            int uid = info.uid;
            String processName = info.processName;
            int[] memoryPid = new int[]{pid};
            Debug.MemoryInfo[] memoryInfo = mActivityManager
                    .getProcessMemoryInfo(memoryPid);
            int memorySize = memoryInfo[0].getTotalPss();

            AMProcessInfo processInfo = new AMProcessInfo();
            processInfo.setPid("" + pid);
            processInfo.setUid("" + uid);
            processInfo.setMemorySize("" + memorySize);
            processInfo.setProcessName(processName);
            mAmProcessInfoList.add(processInfo);
        }
        return mAmProcessInfoList;
    }

效果圖

\

9.4 解析Packages.xml獲取系統信息

在系統初始化的時候,PackageManager的底層實現類PackageManagerService會去掃描系統的一些特定目錄,並且解析其中的Apk文件,同時,Android把它獲取到的應用信息,保存到XML文件中,做成一個應用的花名冊,當系統中的APK安裝、刪除、升級時,它也會被更新

這個packages.xml位於/data/system/目錄下,我們用adb pull命令把他導出來,進行查看分析:

< permissions>標簽
permissions標簽定義了目前系統所有的權限,並分為兩類:系統定義的和Apk定義的

< package>標簽
package代表的是一個apk的屬性,其中各節點的信息含義大致為

name:APK的包名 cadePath:APK安裝路徑,主要在system/app和data/app兩種,前者是廠商定制的Apk,後者是用戶安裝的第三方Apk userid:用戶ID version:版本

< perms>標簽
對應Apk的AndroidManifest文件中的< uses-permission>標簽,記錄Apk的權限信息

9.5 Android安全機制

無知識點

9.5.1 Android安全機制簡介

第一道防線:代碼安全機制——代碼混淆proguard
proguard可以混淆關鍵代碼、替換命名讓破壞者閱讀難,同樣也可以壓縮代碼,優化編譯後的Java字節碼 第二道防線:應用接入權限控制——清單文件權限聲明,權限檢查機制
任何App在使用Android受限資源的時候,都需要顯示向系統聲明所需的權限,只有當一個應用App具有相應的權限,才能申請受限資源的時候,通過權限機制的檢查並使用系統的Binder對象完成對系統服務的調用,但是這道防線也有先天性不足,如以下幾項:
被授予的權限無法停止 在應用聲明App使用權限的時,用戶無法針對部分權限進行限制 權限的聲明機制與用戶的安全理念相關
Android系統通常按照以下順序來檢查操作者的權限:
首先,判斷permission名稱,如果為空則直接返回PERMISSION_DENIED 其次,判斷Uid,如果為0則為root權限,不做權限控制,如果為System Service的Uid則為系統服務,不做權限控制,如果Uid與參數中的請求Uid不同則返回PERMISSION_DENIED 最後,通過調用packagemanageservice.checkUidPermission()方法來判斷該Uid是否具有相應的權限,該方法會去XML的權限列表和系統級的platform.xml中進行查找 第三道防線:應用簽名機制一數字證書
Android中所有的App都會有一個數字證書,這就是App的簽名,數字證書用於保護App的作者和其App的信任關系,只有擁有相同數字簽名的App,才會在升級時被認為是同一App,而且Android系統不會安裝沒有簽名的App 第四道防線:Linux內核層安全機制一一Uid 訪問權限控制
Animid本質是基於Linux內核開發的,所以Android同樣繼承了Linux的安全特性,比如文件系統的權限控制是由user,group,other與讀(r),寫(w),執行(x)的不同組合來實現的,同樣,Android也實現了這套機制,通常情況下,只有System、root用戶才有權限訪問到系統文件,而一般用戶無法訪問 第五道防線:Android虛擬機沙箱機制——沙箱隔流
Android的App運行在虛擬機中,因此才有沙箱機制,可以讓應用之間相互隔離,通常情況下,不同的應用之間不能互相訪問,每個App都有與之對應的Uid,每個App也運行在單獨的虛似機中,與其他應用完全隔離,在實現安全機制的基礎上,也讓應用之間能夠互不影響,即時一個應用崩潰,,也不會導致其他應用異常

9.5.2 Android系統安全隱患

代碼漏洞 Root風險 安全機制不健全 用戶安全意識 Android開發原則與安全

書本列舉的幾個點相信大家也都比較熟悉,所以不做解釋了

9.5.3 Android Apk反編譯

這裡個人的博客有簡單的介紹:Android四大組件——Activity切換效果、殺死進程、殺死所有Activity、安裝及反編譯

9.5.4 Android Apk加密

為了能夠對編譯好的JavaClass文件進行一些保護,通常會用ProGuard混淆代碼:

ProGuard:用無意義的字母來重命名類、字段、方法和屬性 刪除無用的類、字段、方法和屬性,以及刪除沒用的注釋,最大限度地優化字節碼文件

使用ProGuard也簡單,在Android Studio中可以打開build.gradle(Module:app):

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

這裡的minifyEnabled就是打開ProGuard的開關,proGuardFiles屬於配置混淆文件,分為兩部分:

使用默認的混淆文件,位於< SDK目錄>/tools/proguard/proguard-android.txt目錄下 使用自定義混淆文件,可以在項目的App文件夾找到這個文件,在這個文件裡可以定義引入的第三方依賴包的混淆規則
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved