转载声明.下文出自: https://blog.csdn.net/mingli198611/article/details/17269355/
为什么要关闭组件?
在用到组件时,有时候我们可能暂时性的不使用组件,但又不想把组件kill掉,比如创建了一个broadcastReceiver广播监听器,用来想监听第一次开机启动后获得系统的许多相关信息,并保存在文件中,这样以后每次开机启动就不需要再去启动该服务了,也就是说如果没有把receiver关闭掉,就算是不做数据处理,但程序却还一直在后台运行会消耗电量和内存,这时候就需要把这个receiver给关闭掉。
如何关闭组件?
关闭组件其实并不难,只要创建packageManager对象和ComponentName对象,并调用packageManager对象的setComponentEnabledSetting方法。
public void setComponentEnabledSetting (ComponentName componentName, int newState, int flags)
componentName:组件名称
newState:组件新的状态,可以设置三个值,分别是如下:
不可用状态:COMPONENT_ENABLED_STATE_DISABLED
可用状态:COMPONENT_ENABLED_STATE_ENABLED
默认状态:COMPONENT_ENABLED_STATE_DEFAULT
flags:行为标签,值可以是DONT_KILL_APP或者0。 0说明杀死包含该组件的app
public int getComponentEnabledSetting(ComponentName componentName)
获取组件的状态
实例一:禁止开机启动的Receiver(可以是第三方的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_ENABLED_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);
}
转载声明.下文出自:https://www.cnblogs.com/kunkka/p/9481196.html
1. Disable Package
PackageManager pm = context.getPackageManager(); pm.setApplicationEnabledSetting("com.qualcomm.location", PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
需要system权限以及添加
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
2. Disable Component
PackageManager pm = context.getPackageManager(); ComponentName name = new ComponentName(context, CryptKeeper.class); pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
在frameworks/base/services/java/com/android/server/pm/PackageManagerService.java中有下面一段代码:
// Limit who can change which apps
if (!UserHandle.isSameApp(callingUid, pkgSetting.appId)) {
// Don't allow apps that don't have permission to modify other apps
if (!allowedByPermission
|| filterAppAccessLPr(pkgSetting, callingUid, userId)) {
throw new SecurityException(
"Attempt to change component state; "
+ "pid=" + Binder.getCallingPid()
+ ", uid=" + callingUid
+ (className == null
? ", package=" + packageName
: ", component=" + packageName + "/" + className));
}
可以看出Android不让其他app来禁用另外的app。
想让你在同一个app里操作这个应用的禁用,所以会根据你的uid,判断是不是一个app在做这个操作。
因此,可以看出,系统想让自身来管理自己,所以最好是在自己app中来管理自己被disable。
3. 在 PackageManagerService 中跳过app的安装
PackageManagerService会在第一次启动时遍历/system/app/, /system/priv-app/, system/framework/, /vendor/app/等目录里面是否有需要安装的app,如果有jar或者apk就会把app安装被加在一个list里面。
这样如果我们如果不想app被安装,可以根据app name来跳过当前app的安装。
遍历和安装app的方法在
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
实际安装的方法为:
parallelPackageParser.submit(file, parseFlags);
所以只需要在遍历到不希望装的app时候,continue跳出这个循环,不去走parallelPackageParser.submit(), app就不会被安装
即在这句前面加:
if(file.getName().contains("ABCDE")) { Log.i("Kunkka","Skip ABCDE"); continue; }