2018-04-09應(yīng)用管理

PM掃描安裝過程.png
PackageParser解析流程.png
PackageParser類關(guān)系圖.png
PackageManagerServiceBinder圖.png

應(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)限管理

運(yùn)行時(shí)權(quán)限授權(quán).png

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.grantRuntimePermissionsapp.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);
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市踩麦,隨后出現(xiàn)的幾起案子枚赡,更是在濱河造成了極大的恐慌,老刑警劉巖谓谦,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贫橙,死亡現(xiàn)場離奇詭異,居然都是意外死亡反粥,警方通過查閱死者的電腦和手機(jī)卢肃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來才顿,“玉大人莫湘,你說我怎么就攤上這事≈F” “怎么了幅垮?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長尾组。 經(jīng)常有香客問我忙芒,道長示弓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任呵萨,我火速辦了婚禮奏属,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甘桑。我一直安慰自己,他們只是感情好歹叮,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布跑杭。 她就那樣靜靜地躺著,像睡著了一般咆耿。 火紅的嫁衣襯著肌膚如雪德谅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天萨螺,我揣著相機(jī)與錄音窄做,去河邊找鬼。 笑死慰技,一個(gè)胖子當(dāng)著我的面吹牛椭盏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播吻商,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼掏颊,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了艾帐?” 一聲冷哼從身側(cè)響起乌叶,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柒爸,沒想到半個(gè)月后准浴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捎稚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年乐横,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片今野。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晰奖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出腥泥,到底是詐尸還是另有隱情匾南,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布蛔外,位于F島的核電站蛆楞,受9級(jí)特大地震影響溯乒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜豹爹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一裆悄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧臂聋,春花似錦光稼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肄方,卻和暖如春冰垄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背权她。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工虹茶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人隅要。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓蝴罪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親步清。 傳聞我的和親對(duì)象是個(gè)殘疾皇子洲炊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 面試必背 會(huì)舍棄、總結(jié)概括——根據(jù)我這些年面試和看面試題搜集過來的知識(shí)點(diǎn)匯總而來 建議根據(jù)我的寫的面試應(yīng)對(duì)思路中的...
    luoyangzk閱讀 6,747評(píng)論 6 173
  • 總結(jié)整理了一下android權(quán)限相關(guān)的知識(shí)尼啡,由于篇幅過長暂衡,分為兩篇博客來寫,上篇博客主要是詳解權(quán)限和安全崖瞭,下篇主要...
    Shawn_Dut閱讀 3,775評(píng)論 2 10
  • 2018年Android 面試題 IT開發(fā)仔2018-03-21 15:26:46 在這“金三銀四”的季節(jié)狂巢,我準(zhǔn)備...
    王培921223閱讀 2,511評(píng)論 3 24
  • 1、不安全的隨機(jī)數(shù)生成书聚,在CSRF TOKEN生成唧领、password reset token生成等,會(huì)造成toke...
    nightmare丿閱讀 3,680評(píng)論 0 1
  • 久違的晴天雌续,家長會(huì)斩个。 家長大會(huì)開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了驯杜。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)受啥。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,513評(píng)論 16 22