美文网首页
2018-04-09应用管理

2018-04-09应用管理

作者: uin_sisyphus | 来源:发表于2021-01-04 16:21 被阅读0次
    PM扫描安装过程.png PackageParser解析流程.png PackageParser类关系图.png PackageManagerServiceBinder图.png

    应用管理

    本文主要是分析的是“设置”--> "应用"中的应用管理中的应用的运行时权限和默认应用配置等。
    分析了应用权限管理的整个流程 和 默认应用程序的设置

    一、应用运行时权限管理

    运行时权限授权.png

    Settings --> 应用 --> 配置应用(设置中)--> 应用所需权限
    界面:
    Activity:
    com.android.packageinstaller/.permission.ui.ManagePermissionsActivity
    Fragment:
    com.android.packageinstaller.permission.ui.handheld.ManagePermissionsFragment
    ManagePermissionsFragment有两个,其中一个是针对电视设备的,这里调用的是handheld目录下的文件
    界面很简单,主要利用listView空间来实现。这里重点关注下这里的数据

        //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;
            }
    
            //主要是这个 groups变量,为listView提供数据
            List<PermissionGroup> groups = mPermissions.getGroups();
            PreferenceScreen screen = getPreferenceScreen();
            if (screen == null) {
                screen = getPreferenceManager().createPreferenceScreen(getActivity());
                setPreferenceScreen(screen);
            }
    

    listView的数据主要是由,PermissionGroups对象的getGroups方法获得List<PermissionGroup> , 处理后然后给listView的litem赋值。
    下面看下PermissionGroups怎么构造的数据。
    mPermissions

        //PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroups.java   
        public final class PermissionGroups implements LoaderCallbacks<List<PermissionGroup>> {
            *****
            //构造器
            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提供的处理异步任务的方法,AsyncTaskLoader这里简单介绍下
    loadInBackground()方法执行的耗时操作,通过packageManagerService来获取List<PermissionGroupInfo> groupInfos ,
    获取完成后会回调 LoaderCallbacks接口中的 onLoadFinished()方法。

    所以权限组的产生还在PackageManagerService里面,下面去PackageManagerService.java文件去看下:

    public class PackageManagerService extends IPackageManager.Stub {
        ***
        @Override
        public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) {
            // reader
            synchronized (mPackages) {
            
                // 看来权限组的数据源,要去追踪下mPermissionGroups变量的构造
                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);
                        ****
          }
    

    系统启动PackageManagerService的时候,扫描安装应用的时候,扫描到framework-res.apk文件的时候,解析里面的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对应的数据结构mPermissionGroups

    点击权限组弹出的界面:

    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根据传入的groupName,来返回所有的申请该权限组内权限的应用

        @Override
        public void onPermissionsLoaded(PermissionApps permissionApps) {
                for (PermissionApp app : permissionApps.getApps()) {
                ......
                }
    

    遍历过滤app,然后显示出来

    关闭or授予权限执行的操作

    //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.grantRuntimePermissionsapp.revokeRuntimePermissions();是真正授予或关闭权限的操作

    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;
            }
            
            //转而去调用 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对象封装成 PermissionData(PermissionData是个内部类)
            PermissionData permissionData = ensurePermissionData(permission);
            
            //构建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方法,将该PermissionState对象的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;
            }
    
    

    动态权限写的文件

        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标签对应packageManagerService.java构造器中的

        file: PackageManagerService.java
        public PackageManagerService(Context context, Installer installer,
                boolean factoryTest, boolean onlyCore) {
                ......
            mSettings = new Settings(mPackages);
            //为系统中一些重要的应用提前授予运行时权限
            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);
                }
            }
    

    二、默认应用

    默认应用的一些配置信息都写在了package-restrictions.xml 文件

    默认浏览器配置

    系统记录默认浏览器的位置在:

    手机上的文件位置:data/system/users/0/package-restrictions.xml
        <default-apps>
            <default-browser packageName="com.ucmobile.lite" />
            <default-dialer packageName="com.android.dialer" />
        </default-apps>
    

    源码配置默认浏览器的地方:
    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>
    

    恢复默认浏览器的代码:

    
        //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);
        }
    

    从代码可以看出,系统会去读取frameworks/base/core/res/res/values/config.xml文件中的default_browser参数,来获取默认浏览器的包名,然后查询Settings中有没有该包的信息(没有的话输出错误log),然后调用Settings.setDefaultBrowserPackageNameLPw()方法,最终写入package-restrictions.xml文件的<default-browser >标签。

        //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文件的操作,其中就 包含默认浏览器的标签

      //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);
                //写默认浏览器操作
                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);
                }
            }
        }
        
    

    如下便是写默认浏览器和默认拨号应用的操作,各自对应的标签是<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);
        }
    

    相关文章

      网友评论

          本文标题:2018-04-09应用管理

          本文链接:https://www.haomeiwen.com/subject/dyuihftx.html