PMS 简析
pms 介绍: adb shell pm install -r "/data/local/tmp/com.crg.installtest"
就是安装 apk。 Android系统中PackageManagerService简称PMS,主要负责各种APK的安装,卸载,优化和查询。 pm使用利用adb shell命令,进入Android设备的终端,pm工具在/system/bin中,所以可以直接使用: bullhead:/ $ which pm
/system/bin/pm
pm list packages [options] [FILTER]
打印所有的已经安装的应用的包名,如果设置了文件过滤则值显示包含过滤文字的内容. 127|bullhead:/ $ pm list packages -3
package:com.sohu.inputmethod.sogou
package:com.baidu.searchbox
package:com.crg.installtest
package:com.tencent.mobileqq
package:com.willme.topactivity
安装与卸载apkpm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH]
adb install实际上就是对pm install的封装调用。 包路径pm path package_name 卸载apk:pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE
参数: PMS运行时的一些规则PMS相关的目录与文件,以及PMS操作它们的规则APK文件路径APK主要分为两类: 系统自带的APK 用户安装的第三方APK /system/priv-app android:protectionLevel=signatureOrSystem
那么该app必须放到priv-app目录中去。 安装APK的方法系统应用的安装 通过设备自带的应用商店下载的apk ADB命令安装 第三方应用安装 在ANdroid 5.0之前,Android系统会监视前面所说的几个存放apk的路径,一旦发现有新的apk被放进去了,就会自带安装。5.0之后,不在采取此策略。只有系统启动的时候,才会扫描这写路径中的apk。 apk数据存储的位置 /data/app bullhead:/data/app/com.baidu.searchbox-EeE_6P6R7H8-djrQTbZyxg== # ls -al
total 49676
drwxr-xr-x 4 system system 4096 1970-01-04 23:31 .
drwxrwx--x 7 system system 4096 1970-01-04 23:31 ..
-rw-r--r-- 1 system system 50850328 1970-01-04 23:31 base.apk
drwxr-xr-x 3 system system 4096 1970-01-04 23:31 lib
drwxrwx--x 3 system install 4096 1970-01-04 23:31 oat
oat 目录: bullhead:/data/app/com.baidu.searchbox-EeE_6P6R7H8-djrQTbZyxg==/oat/arm # ls -al
total 31500
drwxrwx--x 2 system install 4096 1970-01-05 00:00 .
drwxrwx--x 3 system install 4096 1970-01-04 23:31 ..
-rw-r----- 1 system all_a66 131072 1970-01-05 00:00 base.art
-rw-r----- 1 system all_a66 3035560 1970-01-04 23:31 base.odex
-rw-r----- 1 system all_a66 29073860 1970-01-05 00:00 base.vdex
在之前的Android版本中,用户安装的app的oat文件存储在 /data/dalvik-cache
中。6.0时,此目录只存放系统自带的apk的oat文件。 bullhead:/data/user # ls -al
total 12
drwx--x--x 2 system system 4096 1970-01-04 22:38 .
drwxrwx--x 41 system system 4096 1970-01-04 22:38 ..
lrwxrwxrwx 1 root root 10 1970-01-04 22:38 0 -> /data/data
PMS的配置文件PMS会产生一些配置文件,用来记录系统当前安装的app,这些文件存储在: /data/system/
记录系统中所有已经安装的应用信息,包括基本信息,签名和权限。 <package name="com.baidu.searchbox" codePath="/data/app/com.baidu.searchbox-EeE_6P6R7H8-djrQTbZyxg==" nativeLibraryPath="/data/app/com.baidu.searchbox-EeE_6P6R7H8-djrQTbZyxg==/lib" primaryCpuAbi="armeabi" publicFlags="945307236" privateFlags="0" ft="147f40e0" it="147f7179" ut="147f7179" version="38274304" userId="10066">
<sigs count="1">
<cert index="5" key="30820253308201bca00302010202044b9dd8e7300d06092a864886f70d0101050500306d310b300906035504061302434e3111300f060355040813085368616e676861693111300f060355040713085368616e6768616931133011060355040a130a426169647520496e632e31133011060355040b130a426169647520496e632e310e300c0603550403130542616964753020170d3130303331353036353131395a180f32303634313231363036353131395a306d310b300906035504061302434e3111300f060355040813085368616e676861693111300f060355040713085368616e6768616931133011060355040a130a426169647520496e632e31133011060355040b130a426169647520496e632e310e300c06035504031305426169647530819f300d06092a864886f70d010101050003818d00308189028181009c7a58a39572c4b379ddfca6765e95d3aec69fe362ce622e629647cf441b9e4b7b695e540fd29b7da7b2ab64793089f2b69112d11ac5776973dd68cff88b671826c1286e57c7294c76c7c118ae41bf9336ff9ae0aa90c65ed7db0749ff137b815b6d3b53abaad72d7817b0b8900caef12eea13d12baf0b8cb30543bfb3489c230203010001300d06092a864886f70d01010505000381810063231fb3859d01f75cd7ed810aa5c08eb8fba5b7b7bf11f2c65ae70aa69365b7c985334a38be2c6712c77a1b8aa09d1ae84b51b0062968734700f795b08a7ff5dd73751cd63254f211cb6386fa733690d826b44c169f76c23b82f813b15c1da47a2be69369cd75bf7cdaa337d2ea38726a778583838409b482efc126f7e668b3" />
</sigs>
<perms>
<item name="android.permission.RESTART_PACKAGES" granted="true" flags="0" />
<item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
<item name="android.permission.MODIFY_AUDIO_SETTINGS" granted="true" flags="0" />
<item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" />
<item name="com.baidu.searchbox.permission.DOWNLOAD_STORY" granted="true" flags="0" />
<item name="android.permission.NFC" granted="true" flags="0" />
<item name="android.permission.CHANGE_NETWORK_STATE" granted="true" flags="0" />
<item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
<item name="android.permission.EXPAND_STATUS_BAR" granted="true" flags="0" />
<item name="com.android.launcher.permission.UNINSTALL_SHORTCUT" granted="true" flags="0" />
<item name="android.permission.BLUETOOTH" granted="true" flags="0" />
<item name="android.permission.GET_TASKS" granted="true" flags="0" />
<item name="android.permission.INTERNET" granted="true" flags="0" />
<item name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" granted="true" flags="0" />
<item name="com.baidu.searchbox.permission.APS_INSTALL" granted="true" flags="0" />
<item name="baidu.push.permission.WRITE_PUSHINFOPROVIDER.com.baidu.searchbox" granted="true" flags="0" />
<item name="android.permission.BROADCAST_STICKY" granted="true" flags="0" />
<item name="android.permission.CHANGE_WIFI_STATE" granted="true" flags="0" />
<item name="android.permission.FLASHLIGHT" granted="true" flags="0" />
<item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
<item name="android.permission.DISABLE_KEYGUARD" granted="true" flags="0" />
<item name="android.permission.SET_WALLPAPER" granted="true" flags="0" />
<item name="android.permission.USE_FINGERPRINT" granted="true" flags="0" />
<item name="android.permission.VIBRATE" granted="true" flags="0" />
<item name="com.baidu.searchbox.permission.MIPUSH_RECEIVE" granted="true" flags="0" />
<item name="android.permission.ACCESS_WIFI_STATE" granted="true" flags="0" />
<item name="com.android.launcher.permission.INSTALL_SHORTCUT" granted="true" flags="0" />
<item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
</perms>
<proper-signing-keyset identifier="9" />
</package>
当操作该文件的时候,总会创建备份文件packages-backup.xml.当正常操作完成的时候,会删除该备份。否则,当PMS下次启动的时候,一旦发现有backup文件,就会优先解析备份文件。 packages.list com.android.camera2 10036 0 /data/user/0/com.android.camera2 default:targetSdkVersion=24 3003
com.baidu.searchbox 10066 0 /data/user/0/com.baidu.searchbox default:targetSdkVersion=26 3002,3003
com.crg.installtest 10062 1 /data/user/0/com.crg.installtest default:targetSdkVersion=25 none
第一列为app的包名。 系统硬件特性和权限PMS启动的时候会从 /system/etc/permissions/
中读取当前Android设备的硬件特性和设定的相关权限。 //系统硬件特性
pm list features
//设备依赖的java库
pm list libraries
//dump包信息
pm dump package_name
多用户管理PMS还要对多用户进行管理。因为安装apk的时候,可以PMS可以指定给某个特定的用户,也可以安装给全部的用户。 权限动态管理Android M 中 允许动态授权和取消App中申请的权限。 pm grant <package_name> <permission>
pm revoke <package_name> <permission>
授权和取消是针对APK中申请的权限的来说的。即APK中没有申请的权限,是没办法通过此命令添加的。 PMS的入口:PMS是由SystemServer启动的。 public static void main(String[] args) {
new SystemServer().run();
}
public SystemServer() {
// Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();
// Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
}
private void run() {
...
// Start services.
try {
traceBeginAndSlog("StartServices");
// 启动系统服务
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
private void startBootstrapServices() {
.........
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext,installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
traceEnd();
这样就找到了分析PMS的入口点,PackageManagerService.java的main方法 public static PackageManagerService main(Context context,Installer installer,boolean factoryTest,boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
PackageManagerService m = new PackageManagerService(context,factoryTest,onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package",m);
return m;
}
main函数中的第二个参数installer负责和native层中的installd守护进程进行socket通信,这里在启动Installer 的时候会有installd创建一些关键目录,后续会详细介绍installd守护进程。 这里主要做了两件事:
PMS构造函数分析之Settings接着创建一个DisplayMetrics对象,用于保存屏幕像素参数。 创建一个Settings对象。 mPermissionReviewRequired = context.getResources().getBoolean(
R.bool.config_permissionReviewRequired);
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
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.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log",LOG_UID,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc",NFC_UID,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth",BLUETOOTH_UID,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell",SHELL_UID,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
Settings构造方法: Settings(Object lock) {
this(Environment.getDataDirectory(),lock);
}
Settings(File dataDir,Object lock) {
mLock = lock;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
mSystemDir = new File(dataDir,"system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,-1,-1);
mSettingsFilename = new File(mSystemDir,"packages.xml");
mBackupSettingsFilename = new File(mSystemDir,"packages-backup.xml");
mPackageListFilename = new File(mSystemDir,"packages.list");
FileUtils.setPermissions(mPackageListFilename,0640,SYSTEM_UID,PACKAGE_INFO_GID);
final File kernelDir = new File("/config/sdcardfs");
mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir,"packages-stopped.xml");
mBackupStoppedPackagesFilename =
dataDir为 mSettings.addSharedUserLPw 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;
}
该方法主要是创建共享UID的相关信息。 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;
}
主要针对普通uid和system uid进行不同处理。 ``` 或者android.uid.phone等,如果不提前创建好,就没办法拥有这些共享uid所具备的权限了。
——————————————————————————————————————————————————————————————————————————————————————————————————————————————
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,"get system config"); SystemConfig systemConfig = SystemConfig.getInstance(); mGlobalGids = systemConfig.getGlobalGids(); mSystemPermissions = systemConfig.getSystemPermissions(); mAvailableFeatures = systemConfig.getAvailableFeatures(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 创建和初始化SystemConfig SystemConfig会读取 /system/etc/permissions 文件夹中的相关文件。 SystemConfig() { 其中rootDirectory是“/system”.oemDirectory是”/oem”.也就是会尝试依次读取
/system/etc/sysconfig 这四个目录中的permission文件。
permission文件的读取是通过readPermissions函数完成的:
void readPermissions(File libraryDir,int permissionFlag) { // Iterate over the files in the directory and scan .xml files File platformFile = null; for (File f : libraryDir.listFiles()) { // We'll read platform.xml last if (f.getPath().endsWith("etc/permissions/platform.xml")) { platformFile = f; continue; } if (!f.getPath().endsWith(".xml")) { Slog.i(TAG,"Non-xml file " + f + " in " + libraryDir + " directory,ignoring"); continue; } if (!f.canRead()) { Slog.w(TAG,"Permissions library file " + f + " cannot be read"); continue; } readPermissionsFromXml(f,permissionFlag); } // Read platform permissions last so it will take precedence if (platformFile != null) { readPermissionsFromXml(platformFile,permissionFlag); } } private void readPermissionsFromXml(File permFile,int permissionFlag) { FileReader permReader = null; try { permReader = new FileReader(permFile); } catch (FileNotFoundException e) { Slog.w(TAG,"Couldn't find or open permissions file " + permFile); return; } “` SystemConfig中有一个ArrayMap的mPermissions变量,创建的PermissionEntry会存入该变量中。而group中的uid则会保存在SystemConfig中的mGlobalGids整型数组中。 assign-permission表示把属性name中的字符串表示的权限赋予属性uid中的用户。uid和name则存入SystemConfig中的SparseArray> 类型的mSystemPermissions变量中。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |