简单对pm disable 执行过程进行分析,未整理,顶贴到100楼会进行整理 深入工作室
如果你手机安装了360手机卫士,并root
进入adb shell执行
shell>su
shell>pm disable com.qihoo360.mobilesafe
360手机卫士就被禁用了,其中360安全卫士有禁止开机启动功能!他是怎样实现的呢?下面就行简单分析
PackageManager.setComponentEnabledSetting()实现
类关系图
Context
ContextWrapper.java 对Context包装类
ContextImpl.java 对Context实现类
Activity.java
ActivitThread
IPackageManager
PackageManagerService extends IPackageManager.Stub 对PackageManager实现
PackageManager
ApplicationPackageManager 包装PackageManagerService
GrantedPermissions 权限mode
PackageSettingBase 包含应用程序信息安装时间,更新时间等
PackageSetting
PackageSignatures 应用签名,保存key
BasePermission
Settings
官方解释:Holds information about dynamic settings.
翻译为:对动态设置的信息
Activity调用getPackagemanager()
@Override
public PackageManager getPackageManager() {
IPackageManager pm = ActivityThread.getPackageManager();
// Doesn't matter if we make more than one instance.
return new ApplicationPackageManager(this, pm);
}
ActivityThread 获取PackageManager
public static IPackageManager getPackageManager() {
IBinder b = ServiceManager.getService("package");
return IPackageManager.Stub.asInterface(b);
}
IPackageManager.aidl 实现类为 PackageManagerService下面是声明
public class PackageManagerService extends IPackageManager.Stub
核心实现代码
Parameters
componentName The component to enable
newState The new enabled state for the component. The legal values for this state are: COMPONENT_ENABLED_STATE_ENABLED, COMPONENT_ENABLED_STATE_DISABLED and 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).
flags Optional behavior flags: DONT_KILL_APP or 0.
public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags) {
setEnabledSetting(componentName.getPackageName(), componentName.getClassName(), newState, flags);
}
//packageName 应用包名
//className 应用类名
//newState COMPONENT_ENABLED_STATE_ENABLED 启用组件
COMPONENT_ENABLED_STATE_DISABLED 禁用组件
COMPONENT_ENABLED_STATE_DEFAULT //TODO ?
COMPONENT_ENABLED_STATE_DISABLED_USER 注在官方文档没有给这个参数,现在这个参数没有用处
//flags DONT_KILL_APP or 0
private void setEnabledSetting( final String packageName, String className, int newState, final int flags) {
//支持状态检测
if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
|| newState == COMPONENT_ENABLED_STATE_ENABLED
|| newState == COMPONENT_ENABLED_STATE_DISABLED
|| newState == COMPONENT_ENABLED_STATE_DISABLED_USER)) {
throw new IllegalArgumentException("Invalid new component state: "
+ newState);
}
PackageSetting pkgSetting;
//用户uid检测,不是root用户你是不能禁用与启用其他应用组件的,但可以修改自己应用组件
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
boolean sendNow = false;
boolean isApp = (className == null);
String componentName = isApp ? packageName : className;
int packageUid = -1;
ArrayList<String> components;
// writer
synchronized (mPackages) {
//根据包名获取应用配置
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
if (className == null) {
throw new IllegalArgumentException(
"Unknown package: " + packageName);
}
throw new IllegalArgumentException(
"Unknown component: " + packageName
+ "/" + className);
}
if (!allowedByPermission && (uid != pkgSetting.userId)) {
throw new SecurityException(
"Permission Denial: attempt to change component state from pid="
+ Binder.getCallingPid()
+ ", uid=" + uid + ", package uid=" + pkgSetting.userId);
}
if (className == null) {
// We're dealing with an application/package level state change
if (pkgSetting.enabled == newState) {
// Nothing to do
return;
}
pkgSetting.enabled = newState;
pkgSetting.pkg.mSetEnabled = newState;
} else {
// We're dealing with a component level state change
//这里得到配置后进行开启与禁用
switch (newState) {
case COMPONENT_ENABLED_STATE_ENABLED:
if (!pkgSetting.enableComponentLPw(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DISABLED:
if (!pkgSetting.disableComponentLPw(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DEFAULT:
if (!pkgSetting.restoreComponentLPw(className)) {
return;
}
break;
default:
Slog.e(TAG, "Invalid new component state: " + newState);
return;
}
}
//保存
mSettings.writeLPr();
packageUid = pkgSetting.userId;
components = mPendingBroadcasts.get(packageName);
final boolean newPackage = components == null;
if (newPackage) {
components = new ArrayList<String>();
}
if (!components.contains(componentName)) {
components.add(componentName);
}
//设置flag,这里影响广播
if ((flags&PackageManager.DONT_KILL_APP) == 0) {
sendNow = true;
// Purge entry from pending broadcast list if another one exists already
// since we are sending one right away.
mPendingBroadcasts.remove(packageName);
} else {
if (newPackage) {
mPendingBroadcasts.put(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) {
sendPackageChangedBroadcast(packageName,
(flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
Settings mSettings = new Settings();
public class Settings{
HashMap<String, PackageSetting> mPackages = new HashMap<String, PackageSetting>();
}
//根据应用获取设置信息
PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
//Settings类
1:初始化缓存集合加载/data/system下的配置文件
packages.xml
packages-backup.xml
packages.list
packages-stopped.xml
packages-stopped-backup.xml
2: 解析内容
3:最配置进行操作然后保存
packages.xml app列表
包名 uid isDebug ? " 1 " : " 0 " app位置
....
com.tencent.mm 10089 0 /data/data/com.tencent.mm
....
判断是否为debug
ApplicationInfo ai = pkg.pkg.applicationInfo;
boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<packages>
<!-- sdk 版本 -->
<last-platform-version internal="15" external="0">
<!-- VerifierDeviceIdentity类 -->
<verifier device="LMJC-3UZX-YWX6-s"/>
<!--XXX知识点:API Guides中介绍了 persimission-trees persimission persimission-group user-persimission -->
<persmission-trees>
<item name="com.google.android.googleapps.permission.GOOGLE_AUTH" package="com.google.android.gsf" >
</permission-trees>
<!--解析所有apk中的AndroidManifest文件获取所有的权限-->
<permissions>
...
<!--
name 权限的名称
package 所在的包
protection 在PermissionInfo中定义取值范围0-3
PermissionInfo.PROTECTION_NORMAL
PermissionInfo.PROTECTION_DANGEROUS
PermissionInfo.PROTECTION_SIGNATURE
PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM
在360xml, android:protectionLevel="signature"可能会影响protection
<permission android:label="access permission" android:name="com.qihoo360.mobilesafe.permission.broadcast"
android:protectionLevel="signature" android:description="@string/app_name" />
-->
<item name="com.google.android.gtalkservice.permission.GTALK_SERVICE" package="com.google.android.gsf" protection="2" />
<item name="android.permission.ACCESS_NETWORK_STATE" package="android" />
<item name="tencent.pengyou.permission.DATA" package="com.tencent.pengyou" protection="2" />
<item name="android.permission.CHANGE_WIFI_MULTICAST_STATE" package="android" protection="1" />
<item name="android.permission.CALL_PRIVILEGED" package="android" protection="3" />
<item name="com.qihoo360.mobilesafe.permission.broadcast" package="com.qihoo360.mobilesafe" protection="2" />
...
</permissions>
<!--
name: 包名
realName: 真实包名
codePath: 安装包路径
resourcePath:
nativeLibraryPath: lib包路径
flags: pkg.pkgFlags
ft: pkg.timeStamp
it: pkg.firstInstallTime 安装时间
ut: pkg.lastUpdateTime 更新时间
version:
userId:
sharedUserId:
uidError:
enabled: 应用被禁用 pm disable com.zhima 启用 pm enable com.zhima
installStatus:
installer:
sigs:
perms:
disabled-components: 禁用的组件
enable-components:
-->
<package name="com.example.demo5" codePath="/data/app/com.example.demo5-1.apk" nativeLibraryPath="/data/data/com.example.demo5/lib" flags="0" ft="13efa2c4770" it="13eede89d9a" ut="13efa2c484a" version="1" userId="10100">
<sigs count="1">
<cert index="1" key="...08201e53082014ea003020102020451208ba5300d06092a864886f70d01010505003037310b30090603550406130255533110300e060355040a1307416e64726f6."/ >
<perms>
<item name="android.permission.SEND_SMS"/>
<item name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<item name="android.permission.ACCESS_WIFI_STATE"/>
<item name="android.permission.ACCESS_COARSE_LOCATION"/>
<item name="android.permission.CALL_PHONE"/>
<item name="android.permission.WRITE_CONTACTS"/>
<item name="android.permission.READ_PHONE_STATE"/>
<item name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<item name="android.permission.SYSTEM_ALERT_WINDOW"/>
<item name="android.permission.CAMERA"/>
<item name="android.permission.INTERNET"/>
<item name="android.permission.CHANGE_WIFI_STATE"/>
<item name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<item name="android.permission.ACCESS_FINE_LOCATION"/>
<item name="android.permission.VIBRATE"/>
<item name="android.permission.BROADCAST_STICKY"/>
<item name="android.permission.ACCESS_NETWORK_STATE"/>
<item name="android.permission.RECORD_AUDIO"/>
<item name="android.permission.WAKE_LOCK"/>
<item name="android.permission.ACCESS_MOCK_LOCATION"/>
<perms>
</package>
</packages>
理解:pm disable com.zhima 执行过程
获取PackageManage调用setComponentEnabledSetting方法,操作Settings对配置文件进行修改
如果你手机安装了360手机卫士,并root
进入adb shell执行
shell>su
shell>pm disable com.qihoo360.mobilesafe
360手机卫士就被禁用了,其中360安全卫士有禁止开机启动功能!他是怎样实现的呢?下面就行简单分析
PackageManager.setComponentEnabledSetting()实现
类关系图
Context
ContextWrapper.java 对Context包装类
ContextImpl.java 对Context实现类
Activity.java
ActivitThread
IPackageManager
PackageManagerService extends IPackageManager.Stub 对PackageManager实现
PackageManager
ApplicationPackageManager 包装PackageManagerService
GrantedPermissions 权限mode
PackageSettingBase 包含应用程序信息安装时间,更新时间等
PackageSetting
PackageSignatures 应用签名,保存key
BasePermission
Settings
官方解释:Holds information about dynamic settings.
翻译为:对动态设置的信息
Activity调用getPackagemanager()
@Override
public PackageManager getPackageManager() {
IPackageManager pm = ActivityThread.getPackageManager();
// Doesn't matter if we make more than one instance.
return new ApplicationPackageManager(this, pm);
}
ActivityThread 获取PackageManager
public static IPackageManager getPackageManager() {
IBinder b = ServiceManager.getService("package");
return IPackageManager.Stub.asInterface(b);
}
IPackageManager.aidl 实现类为 PackageManagerService下面是声明
public class PackageManagerService extends IPackageManager.Stub
核心实现代码
Parameters
componentName The component to enable
newState The new enabled state for the component. The legal values for this state are: COMPONENT_ENABLED_STATE_ENABLED, COMPONENT_ENABLED_STATE_DISABLED and 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).
flags Optional behavior flags: DONT_KILL_APP or 0.
public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags) {
setEnabledSetting(componentName.getPackageName(), componentName.getClassName(), newState, flags);
}
//packageName 应用包名
//className 应用类名
//newState COMPONENT_ENABLED_STATE_ENABLED 启用组件
COMPONENT_ENABLED_STATE_DISABLED 禁用组件
COMPONENT_ENABLED_STATE_DEFAULT //TODO ?
COMPONENT_ENABLED_STATE_DISABLED_USER 注在官方文档没有给这个参数,现在这个参数没有用处
//flags DONT_KILL_APP or 0
private void setEnabledSetting( final String packageName, String className, int newState, final int flags) {
//支持状态检测
if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
|| newState == COMPONENT_ENABLED_STATE_ENABLED
|| newState == COMPONENT_ENABLED_STATE_DISABLED
|| newState == COMPONENT_ENABLED_STATE_DISABLED_USER)) {
throw new IllegalArgumentException("Invalid new component state: "
+ newState);
}
PackageSetting pkgSetting;
//用户uid检测,不是root用户你是不能禁用与启用其他应用组件的,但可以修改自己应用组件
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
boolean sendNow = false;
boolean isApp = (className == null);
String componentName = isApp ? packageName : className;
int packageUid = -1;
ArrayList<String> components;
// writer
synchronized (mPackages) {
//根据包名获取应用配置
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
if (className == null) {
throw new IllegalArgumentException(
"Unknown package: " + packageName);
}
throw new IllegalArgumentException(
"Unknown component: " + packageName
+ "/" + className);
}
if (!allowedByPermission && (uid != pkgSetting.userId)) {
throw new SecurityException(
"Permission Denial: attempt to change component state from pid="
+ Binder.getCallingPid()
+ ", uid=" + uid + ", package uid=" + pkgSetting.userId);
}
if (className == null) {
// We're dealing with an application/package level state change
if (pkgSetting.enabled == newState) {
// Nothing to do
return;
}
pkgSetting.enabled = newState;
pkgSetting.pkg.mSetEnabled = newState;
} else {
// We're dealing with a component level state change
//这里得到配置后进行开启与禁用
switch (newState) {
case COMPONENT_ENABLED_STATE_ENABLED:
if (!pkgSetting.enableComponentLPw(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DISABLED:
if (!pkgSetting.disableComponentLPw(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DEFAULT:
if (!pkgSetting.restoreComponentLPw(className)) {
return;
}
break;
default:
Slog.e(TAG, "Invalid new component state: " + newState);
return;
}
}
//保存
mSettings.writeLPr();
packageUid = pkgSetting.userId;
components = mPendingBroadcasts.get(packageName);
final boolean newPackage = components == null;
if (newPackage) {
components = new ArrayList<String>();
}
if (!components.contains(componentName)) {
components.add(componentName);
}
//设置flag,这里影响广播
if ((flags&PackageManager.DONT_KILL_APP) == 0) {
sendNow = true;
// Purge entry from pending broadcast list if another one exists already
// since we are sending one right away.
mPendingBroadcasts.remove(packageName);
} else {
if (newPackage) {
mPendingBroadcasts.put(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) {
sendPackageChangedBroadcast(packageName,
(flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
Settings mSettings = new Settings();
public class Settings{
HashMap<String, PackageSetting> mPackages = new HashMap<String, PackageSetting>();
}
//根据应用获取设置信息
PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
//Settings类
1:初始化缓存集合加载/data/system下的配置文件
packages.xml
packages-backup.xml
packages.list
packages-stopped.xml
packages-stopped-backup.xml
2: 解析内容
3:最配置进行操作然后保存
packages.xml app列表
包名 uid isDebug ? " 1 " : " 0 " app位置
....
com.tencent.mm 10089 0 /data/data/com.tencent.mm
....
判断是否为debug
ApplicationInfo ai = pkg.pkg.applicationInfo;
boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<packages>
<!-- sdk 版本 -->
<last-platform-version internal="15" external="0">
<!-- VerifierDeviceIdentity类 -->
<verifier device="LMJC-3UZX-YWX6-s"/>
<!--XXX知识点:API Guides中介绍了 persimission-trees persimission persimission-group user-persimission -->
<persmission-trees>
<item name="com.google.android.googleapps.permission.GOOGLE_AUTH" package="com.google.android.gsf" >
</permission-trees>
<!--解析所有apk中的AndroidManifest文件获取所有的权限-->
<permissions>
...
<!--
name 权限的名称
package 所在的包
protection 在PermissionInfo中定义取值范围0-3
PermissionInfo.PROTECTION_NORMAL
PermissionInfo.PROTECTION_DANGEROUS
PermissionInfo.PROTECTION_SIGNATURE
PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM
在360xml, android:protectionLevel="signature"可能会影响protection
<permission android:label="access permission" android:name="com.qihoo360.mobilesafe.permission.broadcast"
android:protectionLevel="signature" android:description="@string/app_name" />
-->
<item name="com.google.android.gtalkservice.permission.GTALK_SERVICE" package="com.google.android.gsf" protection="2" />
<item name="android.permission.ACCESS_NETWORK_STATE" package="android" />
<item name="tencent.pengyou.permission.DATA" package="com.tencent.pengyou" protection="2" />
<item name="android.permission.CHANGE_WIFI_MULTICAST_STATE" package="android" protection="1" />
<item name="android.permission.CALL_PRIVILEGED" package="android" protection="3" />
<item name="com.qihoo360.mobilesafe.permission.broadcast" package="com.qihoo360.mobilesafe" protection="2" />
...
</permissions>
<!--
name: 包名
realName: 真实包名
codePath: 安装包路径
resourcePath:
nativeLibraryPath: lib包路径
flags: pkg.pkgFlags
ft: pkg.timeStamp
it: pkg.firstInstallTime 安装时间
ut: pkg.lastUpdateTime 更新时间
version:
userId:
sharedUserId:
uidError:
enabled: 应用被禁用 pm disable com.zhima 启用 pm enable com.zhima
installStatus:
installer:
sigs:
perms:
disabled-components: 禁用的组件
enable-components:
-->
<package name="com.example.demo5" codePath="/data/app/com.example.demo5-1.apk" nativeLibraryPath="/data/data/com.example.demo5/lib" flags="0" ft="13efa2c4770" it="13eede89d9a" ut="13efa2c484a" version="1" userId="10100">
<sigs count="1">
<cert index="1" key="...08201e53082014ea003020102020451208ba5300d06092a864886f70d01010505003037310b30090603550406130255533110300e060355040a1307416e64726f6."/ >
<perms>
<item name="android.permission.SEND_SMS"/>
<item name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<item name="android.permission.ACCESS_WIFI_STATE"/>
<item name="android.permission.ACCESS_COARSE_LOCATION"/>
<item name="android.permission.CALL_PHONE"/>
<item name="android.permission.WRITE_CONTACTS"/>
<item name="android.permission.READ_PHONE_STATE"/>
<item name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<item name="android.permission.SYSTEM_ALERT_WINDOW"/>
<item name="android.permission.CAMERA"/>
<item name="android.permission.INTERNET"/>
<item name="android.permission.CHANGE_WIFI_STATE"/>
<item name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<item name="android.permission.ACCESS_FINE_LOCATION"/>
<item name="android.permission.VIBRATE"/>
<item name="android.permission.BROADCAST_STICKY"/>
<item name="android.permission.ACCESS_NETWORK_STATE"/>
<item name="android.permission.RECORD_AUDIO"/>
<item name="android.permission.WAKE_LOCK"/>
<item name="android.permission.ACCESS_MOCK_LOCATION"/>
<perms>
</package>
</packages>
理解:pm disable com.zhima 执行过程
获取PackageManage调用setComponentEnabledSetting方法,操作Settings对配置文件进行修改