应用学习
一、PMS的常用功能
- 1、安装、卸载应用
- 2、查询permission相关信息
- 3、查询Application相关信息(application、activity、receiver、service、provider及相应属性等)
- 4、查询已安装应用
- 5、增加、删除permission
- 6、清除用户数据、缓存、代码等
二、接口的讲解
1.PackaeManager.java------>ApplicationPackageManager.java---->PackageManagerService.java
queryIntentActivities(intent, PackageManager.MATCH_ALL); : 查询包含这个Intent的Activity
resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) : 查询是否有满足这个Intent的Activity
clearPackagePreferredActivities() : 清除默认的修改
addPreferredActivity() : 修改默认的配置
if (r.match > bestMatch) bestMatch = r.match;
replacePreferredActivity() : 替换Intent 匹配相同的Activity
getPackageUid(String packageName) : 获取相应包的UID
getPermissionInfo(String packageName, int flags (大部分默认为0)) : 通过包名获取权限
getApplicationInfo(String packageName,int flags) : 检索出一个应用程序的所有信息
getActivityInfo(
ComponentName component,int flags
) : 检索出一个特定的Activity类的所有信息
getPackageInfo(String packageName, int flags) : 包名获取该包名对应的应用程序的PackageInfo对象
getInstalledPackages
(int flags(一般传值为0)) : 返回设备上所有已经安装的应用程序集合
GET_ACTIVITIES :(packageInfo的标志)表示 返回包(packageInfo)中包含的所有Activity信息
GET_GIDS :(packageInfo的标志)表示 返回关联的GID(groupId)
GET_CONFIGURATIONS :(packageInfo的标志)表示 配置选项信息
GET_INSTRUMENTATION :(PackageInfo的标志)表示 是否使用了instrumentation
GET_PERMISSIONS :(PackageInfo的标志)表示 是否使用了permissions
GET_PROVIDERS :(PackageInfo的标志)表示 是否使用了providers
GET_RECEIVERS :(PackageInfo的标志)表示 是否使用了recevier
GET_SERVICES :(PackageInfo的标志)表示 是否使用了service
GET_SIGNATURES :(PackageInf的标志) 表示是否使用包的签名信息
GET_UNINSTALLED_PACKAGES:参数标志位,表示检索出所有有数据的目录的应用程序(主要是卸载的)的信息
IBinder b = ServiceManager.getService("package");
sPackageManager = IPackageManager.Stub.asInterface(b);
方法二:
ActivityThread.getPackageManager()
public void checkCallingOrSelfPermission(String permission) // 检查自己或者其它调用者是否有 permission 权限
三、PackageManagerService的重要成员支持类以及变量
1.PackageParser : 这个类主要用于解析APK,解析其AndroidManifest.xml文件得到package的所有信息。 PackageParser.Package这个类用于容纳解析出的信息。
2. Settings:这个类表示它服务处理设置和读取包的各种状态,它是动态的,比如userId,shareUser、permission、signature以及origPackg相关信息
3. Installer : 这个类协助安装过程
4. final PackageInstallerService mInstallerService: 一个应用的安装时间比较长,Android就是用PackageInstallerService来管理应用的安装过程
5. final Installer mInstaller : 它是Install的实例,用于和Demon进行install交互。实际上系统上进行APK格式转换、建立数据目录等工作,都是install进程来完成的。
6. final Settings mSettings : Setting的实例,保存一些PackageManagner动态设置信息
7. final ArrayMap<String, PackageParser.Package> mPackages : 代表系统已经安装的package
8. final private ArrayMap<String, File> mExpectingBetter : 被升级过的应用列表
9. final SparseArray<HashSet<String>> mSystemPermissions : 系统权限的集合
10. final HashMap<String, String> mSharedLibraries : 当前已知的共享库
11. final boolean mOnlyCore : 用于判断是否只扫描系统库
四、PackageManagerService相关类的学习
1.Settings.java类成员变量
a.private final File mSettingsFilename : 代表的是"/data/system/packages.xml"文件
b.private final File mBackupSettingsFilename:代表的是"/data/system/packages_backup/xml"文件,这个文件不一定存在,如果存在,因为他是备份文件,如果它不存在,则说明上次更新packages.xml文件出错了。
c.private final File mPackageListFilename:代表的是"/data/system/packages.list"文件
final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>(): 是一个ArrayMap的结构,key是包名,value是PackageSetting。PackageSetting主要包含了一个APP的基本信息,如安装位置,lib位置等信息。
d.final ArrayMap<String, SharedUserSetting> mSharedUsers =new ArrayMap<String, SharedUserSetting>():在Android中每一个应用都有一个UID,两个相同的UID的应用可以运行在同一个进程中,所以为了让两个应用运行在一个进程中,往往会在AndroidManifest.xml文件中设置shareUserId这个属性,这个属性就是一个字符串,但是我们知道Linux系统中一个uid是一个整型,所以为了将字符串和整形对应起来,就有了的ShareUserSetting类型,刚才说key是shareUserId这个属性的值,那么值就是SharedUserSetting类型了,ShareUserdSetting中除了name(其实就是key),uid对应Linux系统的uid,还有一个列表字段,记录了当前系统中有相同的shareUserId的应用。
e.final ArrayMap<String, BasePermission> mPermissions=new ArrayMap<String, BasePermission>():代表的是主要保存的是"/system/etc/permissions/platform.xml"中的permission标签内容,因为Android系统是基于Linux系统,所以也有用户组的概念,在platform.xml中定义了一些权限,并且制定了哪些用户具有这些权限,一旦一个应用属于某一个用户组,那么它就拥有了这个用户组的所有权限
ShareUserSetting的架构
......
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName());
if (!isPackage || PackageManagerServiceInjector.ignoreApk(file.getPath())) {
continue;
}
if (RegionalizationEnvironment.isSupported()) {
if (RegionalizationEnvironment.isExcludedApp(file.getName())) {
Log.d(TAG, "Regionalization Excluded:" + file.getName());
continue;
}
}
parallelPackageParser.submit(file, parseFlags); //这里可以过滤掉不想要的app
fileCount++;
}
应用安装:
public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
应用更新:
public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
应用的新版本替代旧版本被安装
public static final String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
应用的新版本替代旧版本被安装,只发给被更新的应用自己
public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
应用卸载:
public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
应用被卸载时发出,正在被卸载的应用自身不会收到
public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
应用被完全卸载时发出(数据被删除)
sendSystemPackageUpdatedBroadcastsInternal() -->看到在广播ACTION_MY_PACKAGE_REPLACED的时候,是通过Intent.setPackage(String packageName)实现定向发送
sendPackageChangedBroadcast
(.....)sendPackageRemovedBroadcastInternal
(.....)Package parseBaseApk(File apkFile, AssetManager assets, int flags):解析AndroidManifast.xml文件
-
PackageParser.parsePackages()是包解析器的入口函数,它首先会判定给定的输入是否为一个目录,如果是目录,则以为着目录下可能存在多个拆分后的APK,这就需要以Cluster的方式进行解析;如果仅仅是一个APK文件,就以Monolithic的方式解析;
-
解析APK,需要先得到一个中间数据结构PacakgeLite,包名、版本、拆分包等信息都会保存在这个数据结构中;由于一个包可能有多个拆分的APK,所以PackageLite可能关联到多个APK,每一个APK都对应到ApkLite这个数据结构,也是一些基本信息的封装。之所以以Lite为后缀命名,是因为这两个数据结构都比较轻量,只保存APK中很少信息;
-
一个APK真正的信息都写在AndroidManifest.xml这个文件中,PackageParser.parseBaseApk()这个函数就是用来解析该文件。其解析过程与AndroidManifest.xml的文件结构一一对应,譬如先解析<application>标签的内容,然后解析其下的<activity>,<service>等标签。
scanPackageLI
: 主要做以下操作://初始化PackageParser对象,用于解析包
PackageParser pp = new PackageParser();
//解析包得到一个PackageParser.Package对象
pkg = pp.parsePackage(scanFile, parseFlags);
//判定系统APK是否需要更新
synchronized (mPackages) {
String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
ps = mSettings.peekPackageLPr(oldName);
} if (ps == null) {
ps = mSettings.peekPackageLPr(pkg.packageName);
}
updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
}
获取APK的签名信息
collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
调用另外一个scanPackageLI()函数,对包进行扫描
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user);
a.//针对包名为“android”的APK进行处理
if (pkg.packageName.equals("android")) {
...
mPlatformPackage = pkg; pkg.mVersionCode = mSdkVersion;
mAndroidApplication = pkg.applicationInfo;
...
}
b. //锁上mPacakges对象,意味着要对这个数据结构进行写操作,里面保存的就是已经解析出来的包信息
synchronized (mPackages) {
// 如果有定义ShareUserId,则创建一个ShareUserSetting对象
if (pkg.mSharedUserId != null) {
suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, true);
if (suid == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Creating application package " + pkg.packageName + " for shared user failed");
}
}
updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo, int flags) : 来更新所有APK的授权状态
包查询的过程:Intent的定义和解析是包查询的核心,通过包查询服务可以获取到一个包的信息
包安装的过程:这个过程是包管理者接纳一个新入成员的体现
posted on 2019-07-19 21:44 zhang11111wei 阅读(649) 评论(0) 编辑 收藏 举报