PackageManagerService的常用方法

getPackageArchiveInfo得到APK包含的信息

    public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags)

参数archiveFilePath表示一个APK文件的绝对路径。注意返回值PackageInfo,包含Package的所有信息,这些信息都是从AndroidManifest.xml文件中获取的。如果没有成功解析这个包,就返回null。

另外注意第二个参数flags,参考如下:

Use any combination of GET_ACTIVITIESGET_GIDSGET_CONFIGURATIONS,GET_INSTRUMENTATIONGET_PERMISSIONSGET_PROVIDERSGET_RECEIVERSGET_SERVICES,GET_SIGNATURES, to modify the data returned.

getPackageAchiveInfo方法源码如下:

    public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
        final PackageParser parser = new PackageParser();
        final File apkFile = new File(archiveFilePath);
        try {
            PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
            if ((flags & GET_SIGNATURES) != 0) {
                parser.collectCertificates(pkg, 0);
                parser.collectManifestDigest(pkg);
            }
            PackageUserState state = new PackageUserState();
            return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
        } catch (PackageParserException e) {
            return null;
        }
    }

getInstalledPackages(int flags)

public abstract List<PackageInfo> getInstalledPackages(int flags):获取安装到设备上的所有包集合,返回List<PackageInfo>对象。
如果flag设置了GET_UNINSTALLED_PACKAGES,则返回对象中包含删除时指定参数DONT_DELETE_DATA的应用。

getApplicationInfo(String packageName, int flags)

检索指定包名的所有信息的ApplicationInfo对象。flags参数可以是GET_META_DATA,GET_SHARED_LIBRARY_FILES,GET_UNINSTALLED_PACKAGES。
如果flags设定了GET_UNINSTALLED_PACKAGES,如果在已安装的应用列表中没有包含指定包,应用信息就从未安装应用(删除时保留数据目录的应用)列表中检索,
            try {
//如果设置了GET_UNINSTALLED_PACKAGES这个flag,并且在已安装应用列表中没有找到这个包名,则从未安装的应用列表中检索。
//也就是说从已安装的应用程序中检索,以及删除时指定DONT_DELETE_DATA标记的应用程序(表示删除时不删除应用数据)
                ApplicationInfo info = context.getPackageManager()
                        .getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
                if(null != info){
                    state = "Installed";
                }
            } catch (NameNotFoundException e) {
                
            }

判断是否为系统应用

    public static boolean isSystemApp(ApplicationInfo appInfo) {
        boolean flag = false;

        if (appInfo != null
                && ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 || (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
            flag = true;
        }
        return flag;
    }

    public static boolean isSystemCoreApp(ApplicationInfo appInfo) {
        boolean flag = false;

        if (appInfo != null && (appInfo.uid < 10000)) {
            flag = true;
        }
        return flag;
    }

setComponentEnabledSetting禁用开启组件

我们先看一下源码中是怎么解释的,如下:

    /**
     * Set the enabled setting for a package component (activity, receiver, service, provider).
     * This setting will override any enabled state which may have been set by the component in its
     * manifest.
     *
     * @param componentName The component to enable
     * @param newState The new enabled state for the component.  The legal values for this state
     *                 are:
     *                   {@link #COMPONENT_ENABLED_STATE_ENABLED},
     *                   {@link #COMPONENT_ENABLED_STATE_DISABLED}
     *                   and
     *                   {@link #COMPONENT_ENABLED_STATE_DEFAULT}
     *                 The last one removes the setting, thereby restoring the component's state to
     *                 whatever was set in it's manifest (or enabled, by default).
     * @param flags Optional behavior flags: {@link #DONT_KILL_APP} or 0.
     */
    public abstract void setComponentEnabledSetting(ComponentName componentName,
            int newState, int flags);


    /**
     * Return the enabled setting for a package component (activity,
     * receiver, service, provider).  This returns the last value set by
     * {@link #setComponentEnabledSetting(ComponentName, int, int)}; in most
     * cases this value will be {@link #COMPONENT_ENABLED_STATE_DEFAULT} since
     * the value originally specified in the manifest has not been modified.
     *
     * @param componentName The component to retrieve.
     * @return Returns the current enabled state for the component.  May
     * be one of {@link #COMPONENT_ENABLED_STATE_ENABLED},
     * {@link #COMPONENT_ENABLED_STATE_DISABLED}, or
     * {@link #COMPONENT_ENABLED_STATE_DEFAULT}.  The last one means the
     * component's enabled state is based on the original information in
     * the manifest as found in {@link ComponentInfo}.
     */
    public abstract int getComponentEnabledSetting(ComponentName componentName);
为什么要关闭组件呢?

在用到组件时,有时候我们可能暂时性地不使用组件,但又不想把组件kill掉。比如创建了一个BroadcastReceiver广播接收器,用来想监听第一次开机启动后获得系统的许多相关信息,并保存在文件中,这样以后每次开机启动就不需要再去启动该服务了。也就是说如果不关闭这个BroadcastReceiver,就算不做数据处理,但程序还会一直在后台运行消耗电量和内存,这时候就需要把BroadcastReceiver关闭掉。

如何关闭组件呢?

关闭组件的方法正是上面说的setComponentEnabledSetting()方法。只要创建PackageManager对象和ComponentName对象,并调用PackageManager对象的setComponentEnableSetting方法就可以了。

public void setComponentEnableSetting(ComponentName componentName, int netState, int flags)

componentName:组件名称;

newState:组件新的状态,可以设置三个值,如下:

COMPONENT_ENABLE_STATE_DEFAULT:默认状态,采用在manifest中设置的值。

COMPONENT_ENABLE_STATE_ENABLED:可用状态。

COMPONENT_ENABLE_STATE_DISABLED:不可用状态。

flags:行为标签,值可以是DONT_KILL_APP或0,0表示杀死含有该组件的APP。

    /**
     * Flag parameter for
     * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
     * that you don't want to kill the app containing the component.  Be careful when you set this
     * since changing component states can make the containing application's behavior unpredictable.不可预知的
     */
    public static final int DONT_KILL_APP = 0x00000001;
public int getCompinentEnabledSetting(ComponentName componentName)

获取组件的状态。

实例一:禁止开机启动BroadcastReceiver(可以是第三方Receiver)

final ComponentName receiver = new ComponentName(context,需要禁止的receiver); 
 final PackageManager pm = context.getPackageManager(); 
 pm.setComponentEnabledSetting(receiver,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP); 

实例二:隐藏应用图标

如果设置一个app的MainActivity的状态为COMPONENT_ENABLE_STATE_DISABLED,则不会在Launcher的程序图标中发现该app。

PackageManager packageManager = getPackageManager();
ComponentName componentName = new ComponentName(this, StartActivity.class);
int res = packageManager.getComponentEnabledSetting(componentName);
if (res == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
           || res == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
    // 隐藏应用图标
    packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                    PackageManager.DONT_KILL_APP);
} else {
    // 显示应用图标
    packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
                    PackageManager.DONT_KILL_APP);
}

setApplicationEnabledSetting()禁用组件

我们先看下在PackageManager中是如何描述的。

    /**
     * Set the enabled setting for an application
     * This setting will override any enabled state which may have been set by the application in
     * its manifest.  It also overrides the enabled state set in the manifest for any of the
     * application's components.  It does not override any enabled state set by
     * {@link #setComponentEnabledSetting} for any of the application's components.
     *
     * @param packageName The package name of the application to enable
     * @param newState The new enabled state for the component.  The legal values for this state
     *                 are:
     *                   {@link #COMPONENT_ENABLED_STATE_ENABLED},
     *                   {@link #COMPONENT_ENABLED_STATE_DISABLED}
     *                   and
     *                   {@link #COMPONENT_ENABLED_STATE_DEFAULT}
     *                 The last one removes the setting, thereby restoring the applications's state to
     *                 whatever was set in its manifest (or enabled, by default).
     * @param flags Optional behavior flags: {@link #DONT_KILL_APP} or 0.
     */
    public abstract void setApplicationEnabledSetting(String packageName,
            int newState, int flags);

setApplicationEnabledSetting()方法用来设置应用程序的enabled状态,可以停用应用程序中的所有组件(设置为disable状态)。注意与setComponentEnableSetting()方法的区别,后者是设置应用程序的某个组件。

跟踪一下源码,看看两者之间的关系。这里以调用setApplicationEnabledSetting(mContext, pkgname, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);为例进行说明,其中0表示flags。最终通过ApplicationPackageManager调用到PackageManagerService的setApplicationEnabledSetting()方法。

    @Override
    public void setApplicationEnabledSetting(String appPackageName,
            int newState, int flags, int userId, String callingPackage) {
        if (!sUserManager.exists(userId)) return;
        if (callingPackage == null) {
            callingPackage = Integer.toString(Binder.getCallingUid());
        }
        setEnabledSetting(appPackageName, null, newState, flags, userId, callingPackage);
    }
接着调用到了setEnabledSetting()方法,如下。其实setComponentEnableSetting()方法内部也是调用的setEnabledSetting方法。

    private void setEnabledSetting(final String packageName, String className, int newState,
            final int flags, int userId, String callingPackage) {
                
        if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
              || newState == COMPONENT_ENABLED_STATE_ENABLED
              || newState == COMPONENT_ENABLED_STATE_DISABLED
              || newState == COMPONENT_ENABLED_STATE_DISABLED_USER
              || newState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
            throw new IllegalArgumentException("Invalid new component state: "
                    + newState);//如果netState不是这几个状态,抛出IllegalArgumentException异常
        }
        PackageSetting pkgSetting;
        final int uid = Binder.getCallingUid();
        final int permission = mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);//是否申请了CHANGE_COMPONENT_ENABLED_STATED权限
        enforceCrossUserPermission(uid, userId, false, true, "set enabled");
        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
        boolean sendNow = false;
        boolean isApp = (className == null);//调用setApplicationEnabledSetting方法时,className为空,isApp为true。
        String componentName = isApp ? packageName : className;//此处component为packageName
        int packageUid = -1;
        ArrayList<String> components;

        // writer
        synchronized (mPackages) {
            pkgSetting = mSettings.mPackages.get(packageName);//获取PackageSetting对象
            if (pkgSetting == null) {//如果包名对应的PackageSetting对象不存在,则抛出非法参数异常
                if (className == null) {
                    throw new IllegalArgumentException(
                            "Unknown package: " + packageName);
                }
                throw new IllegalArgumentException(
                        "Unknown component: " + packageName
                        + "/" + className);
            }
            // Allow root and verify that userId is not being specified by a different user
            if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) {//异常处理
                throw new SecurityException(
                        "Permission Denial: attempt to change component state from pid="
                        + Binder.getCallingPid()
                        + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
            }
            if (className == null) {//setApplicationEnabledSetting()方法的className值为null
                // We're dealing with an application/package level state change处理应用程序的所有组件状态
                if (pkgSetting.getEnabled(userId) == newState) {//返回PackageUserState类的enabled属性
                    // Nothing to do
                    return;//如果属性没有改变,直接返回
                }
                if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                    || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
                    // Don't care about who enables an app.
                    callingPackage = null;//如果状态是default或enabled,不必关心是谁调用的
                }
                pkgSetting.setEnabled(newState, userId, callingPackage);//设置PackageUserState的enabled和lastDisableAppCaller的属性值
                // pkgSetting.pkg.mSetEnabled = newState;
            } else {//setComponentEnableSetting()方法执行这里
                // We're dealing with a component level state change,设置组件级别的状态
                // First, verify that this is a valid class name.首先,验证这是一个有效的类名
                PackageParser.Package pkg = pkgSetting.pkg;
                if (pkg == null || !pkg.hasComponentClassName(className)) {//异常处理
                    if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) {
                        throw new IllegalArgumentException("Component class " + className
                                + " does not exist in " + packageName);
                    } else {
                        Slog.w(TAG, "Failed setComponentEnabledSetting: component class "
                                + className + " does not exist in " + packageName);
                    }
                }
                switch (newState) {
                case COMPONENT_ENABLED_STATE_ENABLED:
                    if (!pkgSetting.enableComponentLPw(className, userId)) {
                        return;//设置PackageUserState对象的disabledComponents和enabledComponents数组;
                    }
                    break;
                case COMPONENT_ENABLED_STATE_DISABLED:
                    if (!pkgSetting.disableComponentLPw(className, userId)) {
                        return;<span style="font-family: Arial, Helvetica, sans-serif;">//设置PackageUserState对象的disabledComponents和enabledComponents数组</span>
                    }
                    break;
                case COMPONENT_ENABLED_STATE_DEFAULT:
                    if (!pkgSetting.restoreComponentLPw(className, userId)) {
                        return;
                    }
                    break;
                default:
                    Slog.e(TAG, "Invalid new component state: " + newState);
                    return;
                }
            }
            mSettings.writePackageRestrictionsLPr(userId);//将/data/system/users/0/package-restrictions-backup.xml文件写入package-restrictions文件
            components = mPendingBroadcasts.get(userId, packageName);//获取该包名下的所有组件(包括enabled、disabled状态的组件)
            final boolean newPackage = components == null;
            if (newPackage) {
                components = new ArrayList<String>();
            }
            if (!components.contains(componentName)) {
                components.add(componentName);
            }
            if ((flags&PackageManager.DONT_KILL_APP) == 0) {//setApplicationEnabledSetting()方法中flags为0
                sendNow = true;
                // Purge entry from pending broadcast list if another one exists already
                // since we are sending one right away.
                mPendingBroadcasts.remove(userId, packageName);//从预发送广播的组件列表中移除
            } else {
                if (newPackage) {
                    mPendingBroadcasts.put(userId, packageName, components);
                }
                if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
                    // Schedule a message
                    mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
                }
            }
        }

        long callingId = Binder.clearCallingIdentity();
        try {
            if (sendNow) {
                packageUid = UserHandle.getUid(userId, pkgSetting.appId);
                sendPackageChangedBroadcast(packageName,
                        (flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);//发送广播
            }
        } finally {
            Binder.restoreCallingIdentity(callingId);
        }
    }

最后调用sendPackageChangedBroadcast()方法,发送广播。此时,killFlag为false。

    private void sendPackageChangedBroadcast(String packageName,
            boolean killFlag, ArrayList<String> componentNames, int packageUid) {
        if (DEBUG_INSTALL)
            Log.v(TAG, "Sending package changed: package=" + packageName + " components="
                    + componentNames);
        Bundle extras = new Bundle(4);
        extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
        String nameList[] = new String[componentNames.size()];
        componentNames.toArray(nameList);
        extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
        extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);//false
        extras.putInt(Intent.EXTRA_UID, packageUid);
        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null, null,
                new int[] {UserHandle.getUserId(packageUid)});
    }

接下来看下sendPackageBroadcast()方法是如何调用的。此时,action=Intent.ACTION_PACKAGE_CHANGED,targetPkg和finishedReceiver都为null。

    static final void sendPackageBroadcast(String action, String pkg,
            Bundle extras, String targetPkg, IIntentReceiver finishedReceiver,
            int[] userIds) {
        IActivityManager am = ActivityManagerNative.getDefault();
        if (am != null) {
            try {
                if (userIds == null) {
                    userIds = am.getRunningUserIds();
                }
                for (int id : userIds) {
                    final Intent intent = new Intent(action,
                            pkg != null ? Uri.fromParts("package", pkg, null) : null);
                    if (extras != null) {
                        intent.putExtras(extras);
                    }
                    if (targetPkg != null) {
                        intent.setPackage(targetPkg);
                    }
                    // Modify the UID when posting to other users
                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
                    if (uid > 0 && UserHandle.getUserId(uid) != id) {
                        uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
                        intent.putExtra(Intent.EXTRA_UID, uid);
                    }
                    intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                    if (DEBUG_BROADCASTS) {
                        RuntimeException here = new RuntimeException("here");
                        here.fillInStackTrace();
                        Slog.d(TAG, "Sending to user " + id + ": "
                                + intent.toShortString(false, true, false, false)
                                + " " + intent.getExtras(), here);
                    }
                    am.broadcastIntent(null, intent, null, finishedReceiver,
                            0, null, null, null, android.app.AppOpsManager.OP_NONE,
                            finishedReceiver != null, false, id);
                }
            } catch (RemoteException ex) {
            }
        }
    }
调用ActivityManager发送广播。

case Intent.ACTION_PACKAGE_CHANGED:
                            Uri data = intent.getData();
                            String ssp;
                            if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                                boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);//false
                                boolean fullUninstall = removed &&
                                        !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);//false
                                if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {//true
                                    forceStopPackageLocked(ssp, UserHandle.getAppId(
                                            intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                            false, true, true, false, fullUninstall, userId,
                                            removed ? "pkg removed" : "pkg changed");调用forceStopPackaageLocked()方法
                                }
                                if (removed) {
                                    sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
                                            new String[] {ssp}, userId);
                                    if (fullUninstall) {
                                        mAppOpsService.packageRemoved(
                                                intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);

                                        // Remove all permissions granted from/to this package
                                        removeUriPermissionsForPackageLocked(ssp, userId, true);

                                        removeTasksByPackageNameLocked(ssp, userId);
                                        if (userId == UserHandle.USER_OWNER) {
                                            mTaskPersister.removeFromPackageCache(ssp);
                                        }
                                    }
                                } else {
                                    removeTasksByRemovedPackageComponentsLocked(ssp, userId);
                                    if (userId == UserHandle.USER_OWNER) {
                                        mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
                                    }
                                }
                            }
                            break;
                    }
                    break;
此时调用forceStopPackageLocked()方法用来停止组件运行。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值