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。

这些封装信息就像我们自己封装的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 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;    }

运行结果:

解析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. Rexsee API介绍:Android屏幕锁定Keyguard
  5. Android(安卓)- Android(安卓)Studio 的 Preview窗口
  6. Android(安卓)NDK入门之Hello Jni
  7. Android(安卓)多渠道定制化打包
  8. Android设置颜色
  9. android 数据持久化简述

随机推荐

  1. android之使用RxJava实现EventBus事件总
  2. Android闪光灯控制Util
  3. java.net.BindException: bind failed: E
  4. Android 自定义弹窗
  5. Android简易音乐播放器实现代码
  6. Android 判断是否是刘海屏
  7. [置顶] Android输入法之——在代码中强制
  8. Android:混淆排除android-support-v4.jar
  9. android 版本更新6.0、7.0和8.0权限适配
  10. Android调用系统功能、apk安装卸载