PackageManagerService构造方法源码片段:
{
/*---------------省略代码------------------*/
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLibInstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
/*学习这个函数*/
readPermissions();
/*Settings构造中的创建的几个文件学习*/
mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);
/*---------------省略代码------------------*/
}
1. readPermissions()
该函数中扫描*.xml,生成对应的权限数据,并保存到相应的变量中。
platform.xml:
其它xml片段:<?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2008 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- This file is used to define the mappings between lower-level system user and group IDs and the higher-level permission names managed by the platform. Be VERY careful when editing this file! Mistakes made here can open big security holes. --> <permissions> <!-- ================================================================== --> <!-- ================================================================== --> <!-- ================================================================== --> <!-- The following tags are associating low-level group IDs with permission names. By specifying such a mapping, you are saying that any application process granted the given permission will also be running with the given group ID attached to its process, so it can perform any filesystem (read, write, execute) operations allowed for that group. --> <permission name="android.permission.BLUETOOTH_ADMIN" > <group gid="net_bt_admin" /> </permission> <permission name="android.permission.BLUETOOTH" > <group gid="net_bt" /> </permission> <permission name="android.permission.BLUETOOTH_STACK" > <group gid="net_bt_stack" /> </permission> <permission name="android.permission.NET_TUNNELING" > <group gid="vpn" /> </permission> <permission name="android.permission.INTERNET" > <group gid="inet" /> </permission> <permission name="android.permission.CAMERA" > <group gid="camera" /> </permission> <permission name="android.permission.READ_LOGS" > <group gid="log" /> </permission> <permission name="android.permission.READ_EXTERNAL_STORAGE" > <group gid="sdcard_r" /> </permission> <permission name="android.permission.WRITE_EXTERNAL_STORAGE" > <group gid="sdcard_rw" /> </permission> <permission name="android.permission.WRITE_MEDIA_STORAGE" > <group gid="media_rw" /> </permission> <permission name="android.permission.ACCESS_MTP" > <group gid="mtp" /> </permission> <permission name="android.permission.NET_ADMIN" > <group gid="net_admin" /> </permission> <!-- The group that /cache belongs to, linked to the permission set on the applications that can access /cache --> <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" > <group gid="cache" /> </permission> <!-- RW permissions to any system resources owned by group 'diag'. This is for carrier and manufacture diagnostics tools that must be installable from the framework. Be careful. --> <permission name="android.permission.DIAGNOSTIC" > <group gid="input" /> <group gid="diag" /> </permission> <!-- Group that can read detailed network usage statistics --> <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"> <group gid="net_bw_stats" /> </permission> <!-- Group that can modify how network statistics are accounted --> <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING"> <group gid="net_bw_acct" /> </permission> <!-- Permissions to read DRM-protected theme resources. --> <permission name="com.tmobile.permission.ACCESS_DRM_THEME" > <group gid="theme_manager" /> </permission> <!-- ================================================================== --> <!-- ================================================================== --> <!-- ================================================================== --> <!-- The following tags are assigning high-level permissions to specific user IDs. These are used to allow specific core system users to perform the given operations with the higher-level framework. For example, we give a wide variety of permissions to the shell user since that is the user the adb shell runs under and developers and others should have a fairly open environment in which to interact with the system. --> <!-- Standard permissions granted to the shell. --> <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" /> <assign-permission name="android.permission.SEND_SMS" uid="shell" /> <assign-permission name="android.permission.CALL_PHONE" uid="shell" /> <assign-permission name="android.permission.READ_CONTACTS" uid="shell" /> <assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" /> <assign-permission name="android.permission.READ_CALENDAR" uid="shell" /> <assign-permission name="android.permission.WRITE_CALENDAR" uid="shell" /> <assign-permission name="android.permission.READ_USER_DICTIONARY" uid="shell" /> <assign-permission name="android.permission.WRITE_USER_DICTIONARY" uid="shell" /> <assign-permission name="android.permission.ACCESS_FINE_LOCATION" uid="shell" /> <assign-permission name="android.permission.ACCESS_COARSE_LOCATION" uid="shell" /> <assign-permission name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" uid="shell" /> <assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" /> <assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" /> <assign-permission name="android.permission.BLUETOOTH" uid="shell" /> <assign-permission name="android.permission.EXPAND_STATUS_BAR" uid="shell" /> <!-- System tool permissions granted to the shell. --> <assign-permission name="android.permission.GET_TASKS" uid="shell" /> <assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" /> <assign-permission name="android.permission.REORDER_TASKS" uid="shell" /> <assign-permission name="android.permission.SET_ANIMATION_SCALE" uid="shell" /> <assign-permission name="android.permission.SET_PREFERRED_APPLICATIONS" uid="shell" /> <assign-permission name="android.permission.WRITE_SETTINGS" uid="shell" /> <assign-permission name="android.permission.WRITE_SECURE_SETTINGS" uid="shell" /> <assign-permission name="android.permission.BROADCAST_STICKY" uid="shell" /> <!-- Development tool permissions granted to the shell. --> <assign-permission name="android.permission.SET_DEBUG_APP" uid="shell" /> <assign-permission name="android.permission.SET_PROCESS_LIMIT" uid="shell" /> <assign-permission name="android.permission.SET_ALWAYS_FINISH" uid="shell" /> <assign-permission name="android.permission.DUMP" uid="shell" /> <assign-permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES" uid="shell" /> <assign-permission name="android.permission.KILL_BACKGROUND_PROCESSES" uid="shell" /> <!-- Internal permissions granted to the shell. --> <assign-permission name="android.permission.FORCE_BACK" uid="shell" /> <assign-permission name="android.permission.BATTERY_STATS" uid="shell" /> <assign-permission name="android.permission.INTERNAL_SYSTEM_WINDOW" uid="shell" /> <assign-permission name="android.permission.INJECT_EVENTS" uid="shell" /> <assign-permission name="android.permission.RETRIEVE_WINDOW_CONTENT" uid="shell" /> <assign-permission name="android.permission.SET_ACTIVITY_WATCHER" uid="shell" /> <assign-permission name="android.permission.READ_INPUT_STATE" uid="shell" /> <assign-permission name="android.permission.SET_ORIENTATION" uid="shell" /> <assign-permission name="android.permission.INSTALL_PACKAGES" uid="shell" /> <assign-permission name="android.permission.CLEAR_APP_USER_DATA" uid="shell" /> <assign-permission name="android.permission.DELETE_CACHE_FILES" uid="shell" /> <assign-permission name="android.permission.DELETE_PACKAGES" uid="shell" /> <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="shell" /> <assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" /> <assign-permission name="android.permission.DEVICE_POWER" uid="shell" /> <assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" /> <assign-permission name="android.permission.BACKUP" uid="shell" /> <assign-permission name="android.permission.FORCE_STOP_PACKAGES" uid="shell" /> <assign-permission name="android.permission.STOP_APP_SWITCHES" uid="shell" /> <assign-permission name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" uid="shell" /> <assign-permission name="android.permission.GRANT_REVOKE_PERMISSIONS" uid="shell" /> <assign-permission name="android.permission.SET_KEYBOARD_LAYOUT" uid="shell" /> <assign-permission name="android.permission.GET_DETAILED_TASKS" uid="shell" /> <assign-permission name="android.permission.SET_SCREEN_COMPATIBILITY" uid="shell" /> <assign-permission name="android.permission.READ_EXTERNAL_STORAGE" uid="shell" /> <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" /> <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="shell" /> <assign-permission name="android.permission.INTERACT_ACROSS_USERS_FULL" uid="shell" /> <assign-permission name="android.permission.MANAGE_USERS" uid="shell" /> <assign-permission name="android.permission.BLUETOOTH_STACK" uid="shell" /> <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" /> <assign-permission name="android.permission.ACCESS_DRM" uid="media" /> <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" /> <assign-permission name="android.permission.WAKE_LOCK" uid="media" /> <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" /> <!-- This is a list of all the libraries available for application code to link against. --> <library name="android.test.runner" file="/system/framework/android.test.runner.jar" /> <library name="javax.obex" file="/system/framework/javax.obex.jar"/> </permissions>
这些feature标签用来描述一个手持式终端应该支持的硬件特性。<permission> <feature name="android.hardware.camera"/> <feature name="android.hardware.location"/> <feature name="android.hardware.bluetooth"/> <feature name="android.hardware.touchscreen"/> </permission>
扫描解析涉及的xml标签
<permission>
<group>
<assign-permission>
<library>
<feature>
private void readPermissionsFromXml(File permFile) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);
} catch (FileNotFoundException e) {
Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
return;
}
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(permReader);
XmlUtils.beginDocument(parser, "permissions");
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String name = parser.getName();
if ("group".equals(name)) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = Integer.parseInt(gidStr);
/*
猜测也是为了提高效率设计的
*/
mGlobalGids = appendInt(mGlobalGids, gid);
} else {
Slog.w(TAG, "<group> without gid at "
+ parser.getPositionDescription());
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("permission".equals(name)) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
Slog.w(TAG, "<permission> without name at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
/*
Linux gid<--->android权限映射关系在下面的函数中完成存储
*/
readPermission(parser, perm);
} else if ("assign-permission".equals(name)) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
Slog.w(TAG, "<assign-permission> without name at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
String uidStr = parser.getAttributeValue(null, "uid");
if (uidStr == null) {
Slog.w(TAG, "<assign-permission> without uid at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
/*
根据android权限,获取Linux用户权限
*/
int uid = Process.getUidForName(uidStr);
if (uid < 0) {
Slog.w(TAG, "<assign-permission> with unknown uid \""
+ uidStr + "\" at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
HashSet<String> perms = mSystemPermissions.get(uid);
if (perms == null) {
perms = new HashSet<String>();
mSystemPermissions.put(uid, perms);
}
perms.add(perm);
XmlUtils.skipCurrentTag(parser);
} else if ("library".equals(name)) {
String lname = parser.getAttributeValue(null, "name");
String lfile = parser.getAttributeValue(null, "file");
if (lname == null) {
Slog.w(TAG, "<library> without name at "
+ parser.getPositionDescription());
} else if (lfile == null) {
Slog.w(TAG, "<library> without file at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got library " + lname + " in " + lfile);
mSharedLibraries.put(lname, lfile);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("feature".equals(name)) {
String fname = parser.getAttributeValue(null, "name");
if (fname == null) {
Slog.w(TAG, "<feature> without name at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got feature " + fname);
FeatureInfo fi = new FeatureInfo();
fi.name = fname;
mAvailableFeatures.put(fname, fi);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else {
XmlUtils.skipCurrentTag(parser);
continue;
}
}
permReader.close();
} catch (XmlPullParserException e) {
Slog.w(TAG, "Got execption parsing permissions.", e);
} catch (IOException e) {
Slog.w(TAG, "Got execption parsing permissions.", e);
}
}
void readPermission(XmlPullParser parser, String name)
throws IOException, XmlPullParserException {
name = name.intern();
/*
建立Linux gid和Android权限之间的映射关系
mSettings.mPermissions: HashMap<String, BasePermission>
name: "android.permission.xxxxxx"
*/
BasePermission bp = mSettings.mPermissions.get(name);
if (bp == null) {
bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);
mSettings.mPermissions.put(name, bp);
}
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG
|| type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if ("group".equals(tagName)) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = Process.getGidForName(gidStr);
/*
android权限对应的Linux gid权限存放在bp.gids里面
gids:int[]
*/
bp.gids = appendInt(bp.gids, gid);
} else {
Slog.w(TAG, "<group> without gid at "
+ parser.getPositionDescription());
}
}
XmlUtils.skipCurrentTag(parser);
}
}
执行完得到的数据:
mGlobalGirds: int[], 用于存储XML中标签定义的gid;
mSystemPermissions: SparseArray<HashSet<String>>,UID为索引,存储一个字符串HashSet集合,用于描述描述指定UID所拥有的权限,解析<assign-permission>标签获得。
mSettings.mPermission: HashMap<string, BasePermission>, 解析<permission>标签获得,key为权限名,value为BasePermission对象,该对象中有一个gid数组,解析<permission>标签中的<group>标签是会存储对应的gid到该数组中。
mSharedLibraries: HashMap<String, String> , 解析<library>标签获得,key为库名字,value为库的位置。
mAvailableFeatures: HashMap<String, FeatureInfo>, 解析<feature>标签的到,key为feature的字符串描述,value为FeatureInfo对象。
2. Settings构造中创建的几个文件
/*
这里公有5个文件:
packages.xml / packages-backup.xml
--用于记录系统安装Package信息,backup是临时文件
--PKMS先把数据写到临时文件中,等信息写完后,再将文件重命名,这样做的目的是防止在写文件过程中出错,
--导致信息丢失。
packagee-stopped.xml / packages-stopped-backup.xml
--用于记录系统中强制停止运行的Package信息,backup也是临时文件,如果此处存在临时文件,表明此前系统
--因为某种原因中断了正常流程
packages.list
--列出当前系统中应用级(UID > 10000)Package的信息
*/
Settings(Context context, File dataDir) {
mContext = context;
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");
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}
1> packages.xml: PKMS扫描完目标文件夹后会创建该文件。当系统进行程序安装,卸载,更新等操作时,都会更新该文件。该文件保存了系统与Package相关的一些信息。
2> packages.list: 描述系统中所有的非系统自带的APK的信息,当这些程序发生变化的时候,均会更新该文件。
3> packages-stopped.xml: 从系统自带的设置程序中进入应用程序页面,然后再强制停止某个应用时,系统会将该应用的相关信息记录到此文件中,也就是该文件中保存被用户强制停止的Package信息