應(yīng)用管理
本文主要是分析的是“設(shè)置”--> "應(yīng)用"中的應(yīng)用管理中的應(yīng)用的運(yùn)行時(shí)權(quán)限和默認(rèn)應(yīng)用配置等。
分析了應(yīng)用權(quán)限管理的整個(gè)流程 和 默認(rèn)應(yīng)用程序的設(shè)置
一幻馁、應(yīng)用運(yùn)行時(shí)權(quán)限管理
Settings --> 應(yīng)用 --> 配置應(yīng)用(設(shè)置中)--> 應(yīng)用所需權(quán)限
界面:
Activity:
com.android.packageinstaller/.permission.ui.ManagePermissionsActivity
Fragment:
com.android.packageinstaller.permission.ui.handheld.ManagePermissionsFragment
ManagePermissionsFragment有兩個(gè)脓钾,其中一個(gè)是針對(duì)電視設(shè)備的售睹,這里調(diào)用的是handheld目錄下的文件
界面很簡單,主要利用listView空間來實(shí)現(xiàn)可训。這里重點(diǎn)關(guān)注下這里的數(shù)據(jù)
//com.android.packageinstaller.permission.ui.handheld.ManagePermissionsFragment.java
private PermissionGroups mPermissions;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
****
//mPermissions的由來
mPermissions = new PermissionGroups(getActivity(), getLoaderManager(), this);
}
private void updatePermissionsUi() {
Context context = getActivity();
if (context == null) {
return;
}
//主要是這個(gè) groups變量昌妹,為listView提供數(shù)據(jù)
List<PermissionGroup> groups = mPermissions.getGroups();
PreferenceScreen screen = getPreferenceScreen();
if (screen == null) {
screen = getPreferenceManager().createPreferenceScreen(getActivity());
setPreferenceScreen(screen);
}
listView的數(shù)據(jù)主要是由捶枢,PermissionGroups對(duì)象的getGroups方法獲得List<PermissionGroup>
, 處理后然后給listView的litem賦值。
下面看下PermissionGroups怎么構(gòu)造的數(shù)據(jù)飞崖。
mPermissions
//PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroups.java
public final class PermissionGroups implements LoaderCallbacks<List<PermissionGroup>> {
*****
//構(gòu)造器
public PermissionGroups(Context context, LoaderManager loaderManager,
PermissionsGroupsChangeCallback callback) {
mContext = context;
mLoaderManager = loaderManager;
mCallback = callback;
}
@Override
public void onLoadFinished(Loader<List<PermissionGroup>> loader,
List<PermissionGroup> groups) {
if (mGroups.equals(groups)) {
return;
}
mGroups.clear();
mGroups.addAll(groups);
mCallback.onPermissionGroupsChanged();
}
private static final class PermissionsLoader extends AsyncTaskLoader<List<PermissionGroup>> {
public PermissionsLoader(Context context) {
super(context);
}
@Override
public List<PermissionGroup> loadInBackground() {
****
PackageManager packageManager = getContext().getPackageManager();
List<PermissionGroupInfo> groupInfos = packageManager.getAllPermissionGroups(0);
這里使用了Android提供的處理異步任務(wù)的方法烂叔,AsyncTaskLoader這里簡單介紹下
loadInBackground()方法執(zhí)行的耗時(shí)操作,通過packageManagerService來獲取List<PermissionGroupInfo> groupInfos
,
獲取完成后會(huì)回調(diào) LoaderCallbacks接口中的 onLoadFinished()方法固歪。
所以權(quán)限組的產(chǎn)生還在PackageManagerService里面蒜鸡,下面去PackageManagerService.java文件去看下:
public class PackageManagerService extends IPackageManager.Stub {
***
@Override
public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) {
// reader
synchronized (mPackages) {
// 看來權(quán)限組的數(shù)據(jù)源,要去追蹤下mPermissionGroups變量的構(gòu)造
final int N = mPermissionGroups.size();
ArrayList<PermissionGroupInfo> out
= new ArrayList<PermissionGroupInfo>(N);
for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) {
out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
}
return new ParceledListSlice<>(out);
}
}
***
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
****
for (i=0; i<N; i++) {
PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
final String curPackageName = cur == null ? null : cur.info.packageName;
final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
if (cur == null || isPackageUpdate) {
//mPermissionGroups變量賦值的地方
mPermissionGroups.put(pg.info.name, pg);
****
}
系統(tǒng)啟動(dòng)PackageManagerService的時(shí)候牢裳,掃描安裝應(yīng)用的時(shí)候逢防,掃描到framework-res.apk文件的時(shí)候,解析里面的AndroidManifest.xml文件
<!-- Used for runtime permissions related to contacts and profiles on this
device. -->
<permission-group android:name="android.permission-group.CONTACTS"
android:icon="@drawable/perm_group_contacts"
android:label="@string/permgrouplab_contacts"
android:description="@string/permgroupdesc_contacts"
android:priority="100" />
<!-- Used for runtime permissions related to user's calendar. -->
<permission-group android:name="android.permission-group.CALENDAR"
android:icon="@drawable/perm_group_calendar"
android:label="@string/permgrouplab_calendar"
android:description="@string/permgroupdesc_calendar"
android:priority="200" />
<!-- Used for runtime permissions related to user's SMS messages. -->
<permission-group android:name="android.permission-group.SMS"
android:icon="@drawable/perm_group_sms"
android:label="@string/permgrouplab_sms"
android:description="@string/permgroupdesc_sms"
android:priority="300" />
<!-- Used for runtime permissions related to user's SMS messages. -->
<permission-group android:name="android.permission-group.SMS"
android:icon="@drawable/perm_group_sms"
android:label="@string/permgrouplab_sms"
android:description="@string/permgroupdesc_sms"
android:priority="300" />
<!-- Used for runtime permissions related to the shared external storage. -->
<permission-group android:name="android.permission-group.STORAGE"
android:icon="@drawable/perm_group_storage"
android:label="@string/permgrouplab_storage"
android:description="@string/permgroupdesc_storage"
android:priority="900" />
<!-- Used for permissions that allow accessing the device location. -->
<permission-group android:name="android.permission-group.LOCATION"
android:icon="@drawable/perm_group_location"
android:label="@string/permgrouplab_location"
android:description="@string/permgroupdesc_location"
android:priority="400" />
<!-- Used for permissions that are associated telephony features. -->
<permission-group android:name="android.permission-group.PHONE"
android:icon="@drawable/perm_group_phone_calls"
android:label="@string/permgrouplab_phone"
android:description="@string/permgroupdesc_phone"
android:priority="500" />
<!-- Used for permissions that are associated with accessing
microphone audio from the device. Note that phone calls also capture audio
but are in a separate (more visible) permission group. -->
<permission-group android:name="android.permission-group.MICROPHONE"
android:icon="@drawable/perm_group_microphone"
android:label="@string/permgrouplab_microphone"
android:description="@string/permgroupdesc_microphone"
android:priority="600" />
<!-- Used for permissions that are associated with accessing
camera or capturing images/video from the device. -->
<permission-group android:name="android.permission-group.CAMERA"
android:icon="@drawable/perm_group_camera"
android:label="@string/permgrouplab_camera"
android:description="@string/permgroupdesc_camera"
android:priority="700" />
<!-- Used for permissions that are associated with accessing
camera or capturing images/video from the device. -->
<permission-group android:name="android.permission-group.SENSORS"
android:icon="@drawable/perm_group_sensors"
android:label="@string/permgrouplab_sensors"
android:description="@string/permgroupdesc_sensors"
android:priority="800" />
2. xml對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)mPermissionGroups
點(diǎn)擊權(quán)限組彈出的界面:
PermissionAppsFragments.java文件
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setLoading(true /* loading */, false /* animate */);
****
String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
mPermissionApps = new PermissionApps(getActivity(), groupName, this);
mPermissionApps.refresh(true);
}
PermissionApps根據(jù)傳入的groupName,來返回所有的申請(qǐng)?jiān)摍?quán)限組內(nèi)權(quán)限的應(yīng)用
@Override
public void onPermissionsLoaded(PermissionApps permissionApps) {
for (PermissionApp app : permissionApps.getApps()) {
......
}
遍歷過濾app,然后顯示出來
關(guān)閉or授予權(quán)限執(zhí)行的操作
//PackageInstaller/src/com/android/packageinstaller/permission/ui/handheld/PermissionAppsFragment.java
public final class PermissionAppsFragment extends PermissionsFrameFragment implements Callback,
Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(final Preference preference, Object newValue) {
String pkg = preference.getKey();
final PermissionApp app = mPermissionApps.getApp(pkg);
if (app == null) {
return false;
}
addToggledGroup(app.getPackageName(), app.getPermissionGroup());
if (LocationUtils.isLocationGroupAndProvider(mPermissionApps.getGroupName(),
app.getPackageName())) {
LocationUtils.showLocationDialog(getContext(), app.getLabel());
return false;
}
if (newValue == Boolean.TRUE) {
app.grantRuntimePermissions();
} else {
final boolean grantedByDefault = app.hasGrantedByDefaultPermissions();
if (grantedByDefault || (!app.hasRuntimePermissions() && !mHasConfirmedRevoke)) {
new AlertDialog.Builder(getContext())
.setMessage(grantedByDefault ? R.string.system_warning
: R.string.old_sdk_deny_warning)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.grant_dialog_button_deny_anyway,
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((SwitchPreference) preference).setChecked(false);
app.revokeRuntimePermissions();
if (!grantedByDefault) {
mHasConfirmedRevoke = true;
}
}
})
.show();
return false;
} else {
app.revokeRuntimePermissions();
}
}
return true;
}
其中app.grantRuntimePermissions
和 app.revokeRuntimePermissions();
是真正授予或關(guān)閉權(quán)限的操作
app.grantRuntimePermissions 和 app.revokeRuntimePermissions()
file: PermissionsState.java
/**
* Grant a runtime permission for a given device user.
*
* @param permission The permission to grant.
* @param userId The device user id.
* @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
* or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
* #PERMISSION_OPERATION_FAILURE}.
*/
public int grantRuntimePermission(BasePermission permission, int userId) {
enforceValidUserId(userId);
if (userId == UserHandle.USER_ALL) {
return PERMISSION_OPERATION_FAILURE;
}
//轉(zhuǎn)而去調(diào)用 grantPermission()方法
return grantPermission(permission, userId);
}
private int grantPermission(BasePermission permission, int userId) {
if (hasPermission(permission.name, userId)) {
return PERMISSION_OPERATION_FAILURE;
}
final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
//將permission對(duì)象封裝成 PermissionData(PermissionData是個(gè)內(nèi)部類)
PermissionData permissionData = ensurePermissionData(permission);
//構(gòu)建PermissionState(首次)蒲讯,將PermissionState的mGranted屬性置true
if (!permissionData.grant(userId)) {
return PERMISSION_OPERATION_FAILURE;
}
if (hasGids) {
final int[] newGids = computeGids(userId);
if (oldGids.length != newGids.length) {
return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
}
}
return PERMISSION_OPERATION_SUCCESS;
}
//file: PermissionsState.java
private static final class PermissionData {
....
// grant方法忘朝,將該P(yáng)ermissionState對(duì)象的mGranted屬性置true
public boolean grant(int userId) {
if (!isCompatibleUserId(userId)) {
return false;
}
if (isGranted(userId)) {
return false;
}
PermissionState userState = mUserStates.get(userId);
if (userState == null) {
userState = new PermissionState(mPerm.name);
mUserStates.put(userId, userState);
}
userState.mGranted = true;
return true;
}
動(dòng)態(tài)權(quán)限寫的文件
file: /data/system/users/0/runtime-permissions.xml
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<runtime-permissions fingerprint="Philips/X596/X596:7.1.2/N2G47H/12182002:user/release-keys">
<pkg name="org.codeaurora.gallery">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="20" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="20" />
</pkg>
<pkg name="com.autonavi.minimap">
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="0" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="0" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="0" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="0" />
<item name="android.permission.PROCESS_OUTGOING_CALLS" granted="true" flags="0" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="0" />
</pkg>
<shared-user name="android.uid.systemui">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
<item name="android.permission.CAMERA" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
<shared-user name="android.uid.shell">
<item name="android.permission.READ_CALENDAR" granted="true" flags="30" />
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
<item name="android.permission.SEND_SMS" granted="true" flags="30" />
<item name="android.permission.CALL_PHONE" granted="true" flags="30" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
<item name="android.permission.WRITE_CALENDAR" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
</runtime-permissions>
shared-user標(biāo)簽對(duì)應(yīng)packageManagerService.java構(gòu)造器中的
file: PackageManagerService.java
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
......
mSettings = new Settings(mPackages);
//為系統(tǒng)中一些重要的應(yīng)用提前授予運(yùn)行時(shí)權(quán)限
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
......
}
file: /frameworks/base/services/core/java/com/android/server/pm/Settings.java
private void writePermissionsSync(int userId) {
AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId));
ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
synchronized (mLock) {
mWriteScheduled.delete(userId);
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
String packageName = mPackages.keyAt(i);
PackageSetting packageSetting = mPackages.valueAt(i);
if (packageSetting.sharedUser == null) {
PermissionsState permissionsState = packageSetting.getPermissionsState();
List<PermissionState> permissionsStates = permissionsState
.getRuntimePermissionStates(userId);
if (!permissionsStates.isEmpty()) {
permissionsForPackage.put(packageName, permissionsStates);
}
}
}
final int sharedUserCount = mSharedUsers.size();
for (int i = 0; i < sharedUserCount; i++) {
String sharedUserName = mSharedUsers.keyAt(i);
SharedUserSetting sharedUser = mSharedUsers.valueAt(i);
PermissionsState permissionsState = sharedUser.getPermissionsState();
List<PermissionState> permissionsStates = permissionsState
.getRuntimePermissionStates(userId);
if (!permissionsStates.isEmpty()) {
permissionsForSharedUser.put(sharedUserName, permissionsStates);
}
}
}
FileOutputStream out = null;
try {
out = destination.startWrite();
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(out, StandardCharsets.UTF_8.name());
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
String fingerprint = mFingerprints.get(userId);
if (fingerprint != null) {
serializer.attribute(null, ATTR_FINGERPRINT, fingerprint);
}
final int packageCount = permissionsForPackage.size();
for (int i = 0; i < packageCount; i++) {
String packageName = permissionsForPackage.keyAt(i);
List<PermissionState> permissionStates = permissionsForPackage.valueAt(i);
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, packageName);
writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_PACKAGE);
}
final int sharedUserCount = permissionsForSharedUser.size();
for (int i = 0; i < sharedUserCount; i++) {
String packageName = permissionsForSharedUser.keyAt(i);
List<PermissionState> permissionStates = permissionsForSharedUser.valueAt(i);
serializer.startTag(null, TAG_SHARED_USER);
serializer.attribute(null, ATTR_NAME, packageName);
writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_SHARED_USER);
}
serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
// Now any restored permission grants that are waiting for the apps
// in question to be installed. These are stored as per-package
// TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some
// number of individual permission grant entities.
if (mRestoredUserGrants.get(userId) != null) {
ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants =
mRestoredUserGrants.get(userId);
if (restoredGrants != null) {
final int pkgCount = restoredGrants.size();
for (int i = 0; i < pkgCount; i++) {
final ArraySet<RestoredPermissionGrant> pkgGrants =
restoredGrants.valueAt(i);
if (pkgGrants != null && pkgGrants.size() > 0) {
final String pkgName = restoredGrants.keyAt(i);
serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName);
final int N = pkgGrants.size();
for (int z = 0; z < N; z++) {
RestoredPermissionGrant g = pkgGrants.valueAt(z);
serializer.startTag(null, TAG_PERMISSION_ENTRY);
serializer.attribute(null, ATTR_NAME, g.permissionName);
if (g.granted) {
serializer.attribute(null, ATTR_GRANTED, "true");
}
if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
serializer.attribute(null, ATTR_USER_SET, "true");
}
if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
serializer.attribute(null, ATTR_USER_FIXED, "true");
}
if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
}
serializer.endTag(null, TAG_PERMISSION_ENTRY);
}
serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
}
}
}
}
serializer.endDocument();
destination.finishWrite(out);
if (Build.FINGERPRINT.equals(fingerprint)) {
mDefaultPermissionsGranted.put(userId, true);
}
// Any error while writing is fatal.
} catch (Throwable t) {
Slog.wtf(PackageManagerService.TAG,
"Failed to write settings, restoring backup", t);
destination.failWrite(out);
} finally {
IoUtils.closeQuietly(out);
}
}
二、默認(rèn)應(yīng)用
默認(rèn)應(yīng)用的一些配置信息都寫在了package-restrictions.xml 文件
默認(rèn)瀏覽器配置
系統(tǒng)記錄默認(rèn)瀏覽器的位置在:
手機(jī)上的文件位置:data/system/users/0/package-restrictions.xml
<default-apps>
<default-browser packageName="com.ucmobile.lite" />
<default-dialer packageName="com.android.dialer" />
</default-apps>
源碼配置默認(rèn)瀏覽器的地方:
frameworks/base/core/res/res/values/config.xml
//file: frameworks/base/core/res/res/values/config.xml
<!-- Default web browser. This is the package name of the application that will
be the default browser when the device first boots. Afterwards the user
can select whatever browser app they wish to use as the default.
If this string is empty or the specified package does not exist, then
the behavior will be as though no app was named as an explicit default. -->
<string name="default_browser" translatable="false"></string>
恢復(fù)默認(rèn)瀏覽器的代碼:
//file: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void applyFactoryDefaultBrowserLPw(int userId) {
// The default browser app's package name is stored in a string resource,
// with a product-specific overlay used for vendor customization.
String browserPkg = mContext.getResources().getString(
com.android.internal.R.string.default_browser);
if (!TextUtils.isEmpty(browserPkg)) {
// non-empty string => required to be a known package
PackageSetting ps = mSettings.mPackages.get(browserPkg);
if (ps == null) {
Slog.e(TAG, "Product default browser app does not exist: " + browserPkg);
browserPkg = null;
} else {
mSettings.setDefaultBrowserPackageNameLPw(browserPkg, userId);
}
}
// Nothing valid explicitly set? Make the factory-installed browser the explicit
// default. If there's more than one, just leave everything alone.
if (browserPkg == null) {
calculateDefaultBrowserLPw(userId);
}
}
private void calculateDefaultBrowserLPw(int userId) {
List<String> allBrowsers = resolveAllBrowserApps(userId);
final String browserPkg = (allBrowsers.size() == 1) ? allBrowsers.get(0) : null;
mSettings.setDefaultBrowserPackageNameLPw(browserPkg, userId);
}
從代碼可以看出判帮,系統(tǒng)會(huì)去讀取frameworks/base/core/res/res/values/config.xml
文件中的default_browser參數(shù)辜伟,來獲取默認(rèn)瀏覽器的包名,然后查詢Settings中有沒有該包的信息(沒有的話輸出錯(cuò)誤log)脊另,然后調(diào)用Settings.setDefaultBrowserPackageNameLPw()
方法导狡,最終寫入package-restrictions.xml
文件的<default-browser >標(biāo)簽。
//file: framework/base/services/core/java/com/android/server/pm/Settings.java
boolean setDefaultBrowserPackageNameLPw(String packageName, int userId) {
if (userId == UserHandle.USER_ALL) {
return false;
}
mDefaultBrowserApp.put(userId, packageName);
writePackageRestrictionsLPr(userId);
return true;
}
其中 writePackageRestrictionsLPr(userId)
就是寫package-restrictions.xml
文件的操作偎痛,其中就 包含默認(rèn)瀏覽器的標(biāo)簽
//file: framework/base/services/core/java/com/android/server/pm/Settings.java
void writePackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Writing package restrictions for user=" + userId);
}
// Keep the old stopped packages around until we know the new ones have
// been successfully written.
File userPackagesStateFile = getUserPackagesStateFile(userId);
File backupFile = getUserPackagesStateBackupFile(userId);
new File(userPackagesStateFile.getParent()).mkdirs();
if (userPackagesStateFile.exists()) {
// Presence of backup settings file indicates that we failed
// to persist packages earlier. So preserve the older
// backup for future reference since the current packages
// might have been corrupted.
if (!backupFile.exists()) {
if (!userPackagesStateFile.renameTo(backupFile)) {
Slog.wtf(PackageManagerService.TAG,
"Unable to backup user packages state file, "
+ "current changes will be lost at reboot");
return;
}
} else {
userPackagesStateFile.delete();
Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
}
}
try {
final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile);
final BufferedOutputStream str = new BufferedOutputStream(fstr);
final XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, StandardCharsets.UTF_8.name());
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
for (final PackageSetting pkg : mPackages.values()) {
final PackageUserState ustate = pkg.readUserState(userId);
if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + ustate.enabled);
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, pkg.name);
if (ustate.ceDataInode != 0) {
XmlUtils.writeLongAttribute(serializer, ATTR_CE_DATA_INODE, ustate.ceDataInode);
}
if (!ustate.installed) {
serializer.attribute(null, ATTR_INSTALLED, "false");
}
if (ustate.stopped) {
serializer.attribute(null, ATTR_STOPPED, "true");
}
if (ustate.notLaunched) {
serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
}
if (ustate.hidden) {
serializer.attribute(null, ATTR_HIDDEN, "true");
}
if (ustate.suspended) {
serializer.attribute(null, ATTR_SUSPENDED, "true");
}
if (ustate.blockUninstall) {
serializer.attribute(null, ATTR_BLOCK_UNINSTALL, "true");
}
if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
serializer.attribute(null, ATTR_ENABLED,
Integer.toString(ustate.enabled));
if (ustate.lastDisableAppCaller != null) {
serializer.attribute(null, ATTR_ENABLED_CALLER,
ustate.lastDisableAppCaller);
}
}
if (ustate.domainVerificationStatus !=
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
XmlUtils.writeIntAttribute(serializer, ATTR_DOMAIN_VERIFICATON_STATE,
ustate.domainVerificationStatus);
}
if (ustate.appLinkGeneration != 0) {
XmlUtils.writeIntAttribute(serializer, ATTR_APP_LINK_GENERATION,
ustate.appLinkGeneration);
}
if (!ArrayUtils.isEmpty(ustate.enabledComponents)) {
serializer.startTag(null, TAG_ENABLED_COMPONENTS);
for (final String name : ustate.enabledComponents) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, name);
serializer.endTag(null, TAG_ITEM);
}
serializer.endTag(null, TAG_ENABLED_COMPONENTS);
}
if (!ArrayUtils.isEmpty(ustate.disabledComponents)) {
serializer.startTag(null, TAG_DISABLED_COMPONENTS);
for (final String name : ustate.disabledComponents) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, name);
serializer.endTag(null, TAG_ITEM);
}
serializer.endTag(null, TAG_DISABLED_COMPONENTS);
}
serializer.endTag(null, TAG_PACKAGE);
}
writePreferredActivitiesLPr(serializer, userId, true);
writePersistentPreferredActivitiesLPr(serializer, userId);
writeCrossProfileIntentFiltersLPr(serializer, userId);
//寫默認(rèn)瀏覽器操作
writeDefaultAppsLPr(serializer, userId);
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
serializer.endDocument();
str.flush();
FileUtils.sync(fstr);
str.close();
// New settings successfully written, old ones are no longer
// needed.
backupFile.delete();
FileUtils.setPermissions(userPackagesStateFile.toString(),
FileUtils.S_IRUSR|FileUtils.S_IWUSR
|FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-1, -1);
// Done, all is good!
return;
} catch(java.io.IOException e) {
Slog.wtf(PackageManagerService.TAG,
"Unable to write package manager user packages state, "
+ " current changes will be lost at reboot", e);
}
// Clean up partially written files
if (userPackagesStateFile.exists()) {
if (!userPackagesStateFile.delete()) {
Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: "
+ mStoppedPackagesFilename);
}
}
}
如下便是寫默認(rèn)瀏覽器和默認(rèn)撥號(hào)應(yīng)用的操作旱捧,各自對(duì)應(yīng)的標(biāo)簽是<default-browser/>
和<default-dialer>
//file: framework/base/services/core/java/com/android/server/pm/Settings.java
void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(null, TAG_DEFAULT_APPS);
String defaultBrowser = mDefaultBrowserApp.get(userId);
if (!TextUtils.isEmpty(defaultBrowser)) {
//其中 TAG_DEFAULT_BROWSER = "default-browser"
serializer.startTag(null, TAG_DEFAULT_BROWSER);
serializer.attribute(null, ATTR_PACKAGE_NAME, defaultBrowser);
serializer.endTag(null, TAG_DEFAULT_BROWSER);
}
String defaultDialer = mDefaultDialerApp.get(userId);
if (!TextUtils.isEmpty(defaultDialer)) {
//其中TAG_DEFAULT_DIALER = "default-dialer"
serializer.startTag(null, TAG_DEFAULT_DIALER);
serializer.attribute(null, ATTR_PACKAGE_NAME, defaultDialer);
serializer.endTag(null, TAG_DEFAULT_DIALER);
}
serializer.endTag(null, TAG_DEFAULT_APPS);
}