博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《深入理解Android2》读书笔记(三)
阅读量:6844 次
发布时间:2019-06-26

本文共 6437 字,大约阅读时间需要 21 分钟。

接上篇

PackageManagerService 

PackageManagerService负责系统中Package的管理,应用程序的安装、卸载、信息查询等。

1.IPackageManager接口类中定义了服务端和客户端通信的业务函数,还定义了内部类Stub,该类从Binder派生并实现了IPackageManager接口。

2.PackageManagerService继承自IPackageManager.Stub类,由于Stub类从Binder派生,因此PackageManagerService将作为服务端与Binder通信。

3.Stub类中定义了一个内部类Proxy,该类有一个IBinder类型(实际类型为BinderProxy)的成员变量mRemote,mRemote用于和服务器PackageManagerService通信。

4.IPackageManager接口类似定义了许多业务函数,但是出于安全等方面的考虑,Android对外(即SDK)提供的只是一个子集,该子集被封装在抽象类PackageManager中。客户端一般通过Context的getPackageManager函数返回一个类型为PackageManager对象,该对象的实际类型是PackageManager的子类ApplicationPackageManager。这种基于接口编程的方式,虽然极大降低了模块之间的耦合性,却给代码分析带来了不小的麻烦。

5.ApplicationPackageManager类继承自PackageManager类。它并没有直接参与Binder通信,而是通过mPM成员变量指向一个IPackageManager.Stub.Proxy类型的对象。

public static PackageManagerService main(Context context, Installer installer,        boolean factoryTest, boolean onlyCore) {    PackageManagerService m = new PackageManagerService(context, installer,            factoryTest, onlyCore);    ServiceManager.addService("package", m);    return m;}

PKMS构造函数长达600多行,主要功能:扫描Android系统中几个目标文件夹中的APK,从而建立合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。PKMS将解析APK包中的AndroidManifest.xml,并根据其中声明的Activity标签来创建与此对应的对象加以保管。

以下分析构造函数

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,        SystemClock.uptimeMillis());if (mSdkVersion <= 0) {    Slog.w(TAG, "**** ro.build.version.sdk not set!");}mContext = context;mFactoryTest = factoryTest;mOnlyCore = onlyCore;mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));mMetrics = new DisplayMetrics();mSettings = new Settings(mPackages);mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.log", LOG_UID,        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

Setting

SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {    SharedUserSetting s = mSharedUsers.get(name);    if (s != null) {        if (s.userId == uid) {            return s;        }        PackageManagerService.reportSettingsProblem(Log.ERROR,                "Adding duplicate shared user, keeping first: " + name);        return null;    }    s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);    s.userId = uid;    if (addUserIdLPw(uid, s, name)) {        mSharedUsers.put(name, s);        return s;    }    return null;}

得到SharedUserSetting

1.Setting类定义了一个mSharedUsers成员,它是一个HashMap,以字符串(如android.uid.system)为key,对应的Value是一个SharedUserSetting对象。

2.SharedUserSetting派生自GrantedPermission类,从GrantedPermissions类的命名可知,它和权限有关。SharedUserSetting定义了一个成员变量packages,类型为HashSet,用于保存声明了相同sharedUserId的Package的权限设置信息。

3.每个Package有自己的权限设置。权限的概念由PackageSetting类表达。该类继承自PackagesettingBase,而PackageSettingBase又继承自GrantedPermissions。

4.Settings中还有两个成员,一个是mUserIds,另一个是mOtherUserIds,这两位成员的类型分别是ArrayList和SparseArray。其目的是以UID为索引,得到对应的SharedUserSetting对象。在一般情况下,以索引获取数组元素的速度,比以key获取hashMap中元素的速度要快很多。

private boolean addUserIdLPw(int uid, Object obj, Object name) {    if (uid > Process.LAST_APPLICATION_UID) {        return false;    }    if (uid >= Process.FIRST_APPLICATION_UID) {        int N = mUserIds.size();        final int index = uid - Process.FIRST_APPLICATION_UID;        while (index >= N) {            mUserIds.add(null);            N++;        }        if (mUserIds.get(index) != null) {            PackageManagerService.reportSettingsProblem(Log.ERROR,                    "Adding duplicate user id: " + uid                    + " name=" + name);            return false;        }        mUserIds.set(index, obj);    } else {        if (mOtherUserIds.get(uid) != null) {            PackageManagerService.reportSettingsProblem(Log.ERROR,                    "Adding duplicate shared id: " + uid                            + " name=" + name);            return false;        }        mOtherUserIds.put(uid, obj);    }    return true;}

 

PKMS构造函数第一阶段的工作,就是扫描并解析XML文件,并将其中的信息保存到特定的数据结构中。

PKMS第二阶段的工作就是扫描系统中的APK了,由于需要逐个扫描文件,因此手机上装的程序越多,PKMS的工作量就越大,系统启动速度也就越慢。

PKMS将扫描以下几个目录:

1./system/frameworks:该目录中的文件都是系统库,例如framework.jar、services.jar、framework-res.apk.不过scanDirLI只扫描APK文件,所以framework-res.apk是该目录中唯一“受宠”的文件

2./system/app:该目录下全是默认的系统应用,例如Browser.apk、SettingsProvider.apk等。

3./vendor/app:该目录中的文件由厂商提供,即全是厂商特定的APK文件,目前市面上的厂商都把自己的应用放在/system/app目录下

private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {    final File[] files = dir.listFiles();    if (ArrayUtils.isEmpty(files)) {        Log.d(TAG, "No files in app dir " + dir);        return;    }    if (DEBUG_PACKAGE_SCANNING) {        Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags                + " flags=0x" + Integer.toHexString(parseFlags));    }    for (File file : files) {        final boolean isPackage = (isApkFile(file) || file.isDirectory())                && !PackageInstallerService.isStageName(file.getName());        if (!isPackage) {            // Ignore entries which are not packages            continue;        }        try {            scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,                    scanFlags, currentTime, null);        } catch (PackageManagerException e) {            Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());            // Delete invalid userdata apps            if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&                    e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {                logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);                if (file.isDirectory()) {                    mInstaller.rmPackageDir(file.getAbsolutePath());                } else {                    file.delete();                }            }        }    }}

 

scanPackageLI函数首先调用PackageParser对APK文件进行解析,PackageParse完成了从物理文件到对应数据结构的转换。PackageParser功能单一,就是解析AndroidManifest.xml中的各种标签,

 

转载地址:http://drbul.baihongyu.com/

你可能感兴趣的文章
谁说使用Python你就写不出混乱的代码?
查看>>
网桥和交换机的区别
查看>>
使用Raspcontrol在线查看树莓派各项情况
查看>>
超强JIRA流程图
查看>>
java 导出excel表格
查看>>
android好帖子
查看>>
使用EqualsBuilder和HashCodeBuilder重写equals、hashCode方法
查看>>
合理信息安全设备的选择 选型依据分析
查看>>
操作Visual Studio 2010中的SQL Server数据库比较工具
查看>>
partition underscore
查看>>
component develope
查看>>
通向架构师的道路(二)--之apache tomcat https应用
查看>>
理解会话
查看>>
学习Linux决心书
查看>>
华为使用命令
查看>>
二、Python'核心编程(数字)
查看>>
javamail正文乱码
查看>>
poj2226精妙的构图
查看>>
ubuntu 13.10 创建root图形界面超级用户
查看>>
关于制定通信协议
查看>>