Android系统信息获取

要获取系统的配置信息,通常可以从以下两个方面获取:

  • android.os.Build
  • SystemProperty

android.os.Build

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   //编译时间

SystemProperty

SystemProperty包含了许多系统配置属性值和参数,很多信息与上面通过android.os.Build获取的值是相同的,下面同样列举了一些常用的信息:

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属性

Android系统信息实例

下面通过实例帮助我们了解这些系统信息
通过android.os.Build类,可以直接获得一些Build提供的系统信息,而通过SystemgetProperty(“XXXX”),我们可以访问到系统的属性值:

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文件中,包含了很多RO属性值,打开命令行窗口,进入/System目录,通过cat build.prop命令查看文件信息

  • 还可以通过adb shell的getprop来获取对应的属性值:

进入adb shell,使用getprop ro.build.id获取信息

  • 还有一个非常重要的目录存储系统信息—/proc目录:

命令行模式进入/proc文件目录,使用cat cpuinfo命令打开cpuinfo文件查看系统信息

Android Apk应用信息获取之PackageManager

以上都是获取系统信息的,接下来看看如何获取Apk应用信息。在ADB Shell命令中,提到应用相关的东西,我们会想到两个非常强大的助手PM和AM。

  • PM(PackageManager):主宰着应用的包管理,
  • AM(ActivityManager):主宰着应用的活动管理。

PackageManager

下图中,最里面的框代表整个Activity的信息,系统提供了ActivityInfo类来进行封装。最外面的框代表着整个Mainifest文件中节点的信息,系统提供了PackageInfo来进行封装。而Android系统提供了PackageManager来负责管理所有已安装的App。
Android进阶-Android系统信息与安全机制_第1张图片

这些封装信息就像我们自己封装的Bean对象一样,用来封装程序的相关信息,下面列举一些常用的系统封装信息:

  • ActivityInfo

ActivityInfo封装了在Mainifest文件中<activity></activity>和<rceiver></rceiver>之间的所有信息,包括name、icon、lable、launchMode等。

  • ServiceInfo

ServiceInfo与ActivityInfo类似,它封装了<service></service>之间的所有信息

  • ApplicationInfo

ApplicationInfo也是一样,它封装了<application></application>之间的信息。ApplicationInfo包含了很多Flag。
1. FLAG_SYSTEM:表示为系统应用
2. FLAG_EXTERNAL_STORAGE:表示安装在SDCard上的引用

  • PackageInfo

PackageInfo与前面三个Info类类似,都是封装Mainifest文件的相关节点信息,而PackageInfo包含了所有的Activity、Service等信息。

  • ResolveInfo

ResolveInfo比较特殊,它封装的是包含<intent>信息的上一级信息,所以它可以返回ActivityInfo、ServiceInfo包含<intent>的信息。它可以用来找到那些包含特定Intent条件的信息,如带分享功能、播放功能的应用。

PackageManager经常使用以下的方法:

getPackageManager()   //通过这个方法可以返回一个PackageManager对象getApplicationInfo()   //以ApplicationInfo的形式返回指定包名的ApplicationInfogetApplicationIcon()   //返回指定包名的IcongetInstalledApplications()   //以ApplicationInfo的形式返回安装的应用getInstalledPackages()   //以PackageInfo的形式返回安装的应用queryIntentActivities()   //返回指定Intent的ResolveInfo对象、Activity集合queryIntentServices()   //返回指定Intent的ResolveInfo对象、Service集合resolveActivity()   //返回指定Intent的ActivityresolveService()   //返回指定Intent的Service

下面通过实际的例子来了解一下PackageManager筛选不同类型App的应用。判断App类型的依据,就是利用ApplicationInfo中的FLAG_SYSTEM来判断:

app.flags & ApplicationInfo.FLAG_SYSTEM

通过这样的标志区分,可以判断出以下几种不同的应用类型。

  • 如果当前应用的app.flags & ApplicationInfo.FLAG_SYSTEM!=0,则为系统应用
  • 如果当前应用的app.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;}

其中makeAppInfo()方法是用来保存数据到Bean的一个方法:

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;}

运行结果:
Android进阶-Android系统信息与安全机制_第2张图片

Android Apk应用信息获取之ActivityManager

PackageManager和ActivityManager在使用上各有侧重点,PackageManager重点在于获得应用的包信息,而ActivityManager重点在于获得运行的应用程序信息。
ActivityManager也封装了不少的Bean对象,下面几个是比较重要的:

  • ActivityManager.MemoryInfo

MemoryInfo有几个非常重要的字段:availMem(系统可用内存),totalMem(总内存),threshold(低内存的阈值,即区分是否低内存的临界值),lowMemory(是否处于低内存)

  • Debug.MemoryInfo

这个Debug.MemoryInfo用于统计进程下的内存信息

  • RunningAppProcessInfo

运行进程的信息,存储的字段自然是进程相关的信息,存储的字段有:processName(进程名),pid(进程pid),uid(进程uid),pkgList(该进程下的所有包)

  • RunningServiceInfo

用于封装运行的服务信息,在它里面同样包含了一些服务进程信息,同时还有一些其他信息,activeSince(第一次被激活的时间、方式),foreground(服务是否在后台执行)

下面通过实际的例子来了解一下ActivityManager是如何使用的,与在PackManager中一样,封装一个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;    }

运行结果:
Android进阶-Android系统信息与安全机制_第3张图片

解析Package.xml获取系统信息

在系统初始化的时候,PackageManager的底层实现类PackageManagerService会去扫描系统中的一些特定的目录,并解析其中的Apk文件。同时,Android把它获得的引用信息,保存在XML文件中,做成一个应用的花名册,当系统中的Apk安装、删除、升级时,它也会被更新,这个小册子,就是位于/data/system/目录下的—Packages.xml文件,通过ADB Pull命令可以将它到处本地。

Packages.xml文件是非常复杂的,所以要了解一下这个文件所包含的信息点标签:

  • <permissions>标签

permissions标签定义了目前系统中的所有权限,并分为两类:系统定义的和Apk定义的

  • <package>标签

package代表的是一个Apk的属性,其中各节点的信息含义如下所示:
1. name:APK的包名
2. cadePath:APK安装路径,主要在/system/app和data/app两种,前者是厂商定制的Apk,后者是用户安装的第三方Apk
3. userid:用户ID
4. version:版本

  • <perms>标签

对应Apk的AndroidManifest文件中的<uses-permission>标签,记录Apk的权限信息

Android安全机制

Android安全机制简介

安全不管在哪个平台、那个语言中,都是非常重要的一环。Android开发者在Android系统中建立了五道防线来保护Android系统的安全

  • 第一道防线:代码安全机制—代码混淆proguard

由于Java语言的特殊性,即使是编译成Apk的应用程序也存在被反编译的风险。而proguard则是在代码层面上对Android应用程序App的第一重保护,它可以混淆关键代码、替换命名让破坏者阅读困难,同时也可以压缩代码、优化编译后的Java字节码。

  • 第二道防线:应用接入权限控制AndroidMainifest文件权限声明、权限检查机制

任何应用程序App在使用Android首先资源的时候,都需要显示向系统声明所需要的权限,只有当一个应用App具有相应的权限,才能在申请受限资源的时候,通过权限机制的检查并使用系统的Binder对象完成对系统服务的调用。但是这道防线也有这先天性不足,如下几项:

  1. 被授予的权限无法停止
  2. 在应用声明App使用权限时,用户无法针对部分权限进行限制
  3. 权限的声明机制与用户的安全理念相关

Android系统通常按照以下顺序来检查操作者的权限:

  1. 首先,判断permission名称。如果为空则直接返回PERMISSION_DENIED。
  2. 其次,判断Uid。如果为0则为Root权限,不做权限控制;如果为System
    Server的Uid则为系统服务,不做权限控制;如果Uid与参数中的请求Uid不同,则返回PERMISSION_DENIED。
  3. 最后,通过调用packagemanageservice.checkUidPermission()方法判断该Uid是否具有相应的权限。该方法会去XML的权限列表和系统级的platform.xml中进行查找

通过上面的步骤,Android就确定了使用者是否具有某项使用权限。

  • 第三道防线:应用签名机制—数字证书

Android中所有的App都会有一个数字证书,这就是App的签名,数字证书用于保护App的做着对其App的信任关系,只有拥有相同数字签名的App,才会在升级时被认为是同一App。而且Android系统不会安装没有签名的App。

  • 第四道防线:Linux内核层安全机制—Uid、访问权限控制

Android本质是给予Linux内核开发的,所以Android同样继承了Linux的安全特性,比如文件访问机制,Linux文件系统的权限控制是由user、group、other与读(r)、写(w)、执行(x)的不同组合来实现的,同样,Android也实现了这套机制,通常情况下,只有System、root用户才有权限访问系统文件,而一般用户无法访问。

  • 第五道防线:Android虚拟机沙箱机制—沙箱隔离

Android的App运行在虚拟机中,因此才有沙箱机制,可以让应用之间相互格力。通常情况下,不同的应用之间不能相互访问,每个App都有与之对象的Uid,每个App也运行在单独的虚拟机中,与其他应用完全隔离。在实现安全机制的基础上,也让应用之间能够互不影响,即使一个应用崩溃,也不会导致其他应用异常。

Android系统安全隐患

  • 代码漏洞
  • Root风险
  • 安全机制不健全
  • 用户安全意识
  • Android开发原则与安全

Android Apk反编译

之前的博客有详解:Android-APK反编译的详解

Android Apk加密

由于java字节码的特殊性,使得它非常容易被反编译。因此,为了能够对编译好的JavaClass文件一些保护,通常会使用ProGuard来对Apk进行混淆处理,用无异议的字母来重命名类、字段、方法和属性。当然,ProGuard不仅仅可以用来混淆代码,还可以删除无用的类、字段、方法和属性,以及删除没用的注释,最大限度地优化字节码文件。

在Android Studio中,可以非常方便地使用ProGuard,在Gradle Scripts文件夹下,打开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. android 显示系统 surfaceflinger 分析
  2. 如何使Android应用程序获取系统权限
  3. android 创建文件夹失败
  4. Android中修改系统时间的几种方式
  5. Android从文件目录中写入和读取图片
  6. 布局文件中的笔记

随机推荐

  1. Android(安卓)Gradle plugin升级 3.0.1
  2. android studio 3.0.1依赖butterknife报
  3. NDK Mediacodec
  4. Android(安卓)popupwindow 示例程序一
  5. android简单的多人聊天程序--借助Bmob后
  6. Android(安卓)使用Intent和Bundle传递数
  7. android listview item 被选中背景色设置
  8. 【Android】从无到有:手把手一步步教你自
  9. Android(安卓)蓝牙(九)A2DP基本功能
  10. Android(安卓)studio报错rg.gradle.api.t