Android 安装APK、更新apk、隐藏(hide)apk、解除隐藏(unhide)apk 所对应的广播log
Android版本:Android R(11)
一、用户安装的apk发生更新
public void registerReceiver(Context context) { Slog.d("PMSdddd", "systemReady1"); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGE_REPLACED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); BroadcastReceiver packgeMonitorReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); final String packageName = intent.getData().getSchemeSpecificPart(); final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); final boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false); Slog.d("PMSdddd", "action: " + action + " packageName:" + packageName + " replacing:" + replacing + " dataRemoved:" + dataRemoved); } }; context.registerReceiver(packgeMonitorReceiver, filter); }
adb install apk
Line 52701: 02-01 21:26:23.213 1727 1727 D PMSdddd : action: android.intent.action.PACKAGE_ADDED packageName:com.adobe.reader replacing:false dataRemoved:false
adb shell pm hide apk
Line 53895: 02-01 21:28:22.043 1727 1727 D PMSdddd : action: android.intent.action.PACKAGE_REMOVED packageName:com.adobe.reader replacing:false dataRemoved:false
adb install -r apk
Line 54477: 02-01 21:29:41.550 1727 1727 D PMSdddd : action: android.intent.action.PACKAGE_REMOVED packageName:com.adobe.reader replacing:true dataRemoved:false Line 54512: 02-01 21:29:41.648 1727 1727 D PMSdddd : action: android.intent.action.PACKAGE_ADDED packageName:com.adobe.reader replacing:true dataRemoved:false
adb shell pm unhide apk
Line 55640: 02-01 21:32:25.651 1727 1727 D PMSdddd : action: android.intent.action.PACKAGE_ADDED packageName:com.adobe.reader replacing:false dataRemoved:false
Line 61310: 02-01 21:52:36.395 1727 1727 D PMSdddd : action: android.intent.action.PACKAGE_REMOVED packageName:com.adobe.reader replacing:false dataRemoved:true
总结:
- hide命令:系统会发送广播 android.intent.action.PACKAGE_REMOVED,data数据并不会删除
- unhide命令:系统会发送广播android.intent.action.PACKAGE_ADDED,data数据不会删除
- 更新apk时:
系统先发送广播 android.intent.action.PACKAGE_REMOVED,intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) 获取的值为true
系统随后发送广播android.intent.action.PACKAGE_ADDED,intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) 获取的值也为true
- 卸载apk时:
系统发送广播 android.intent.action.PACKAGE_REMOVED,intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false)获取的值为true
二、系统apk(位于:system/app 目录)发生更新
adb push apk system/app
再恢复出厂设置
Line 8118: 02-02 02:55:59.428 1130 1130 D PMSdddd : action: android.intent.action.PACKAGE_REMOVED packageName:com.example.ddd replacing:true dataRemoved:false Line 8134: 02-02 02:55:59.501 1130 1130 D PMSdddd : action: android.intent.action.PACKAGE_ADDED packageName:com.example.ddd replacing:true dataRemoved:false Line 8281: 02-02 02:55:59.903 1130 1130 D PMSdddd : action: android.intent.action.PACKAGE_REPLACED packageName:com.example.ddd replacing:true dataRemoved:false
更新后的apk安装在 data/app目录:
Line 8550: 02-02 05:12:10.806 1132 1228 I PackageManager: Update system package com.example.ddd code path from /system/operator/app/AndroidDemoV1.0.apk to /data/app/~~IYd549AfrGeHUc-lWfY8kg==/com.example.ddd-o9yTi7O1l3Cm3EhqTvf2Rw==; Retain data and using new Line 8550: 02-02 05:12:10.806 1132 1228 I PackageManager: Update system package com.example.ddd code path from /system/operator/app/AndroidDemoV1.0.apk to /data/app/~~IYd549AfrGeHUc-lWfY8kg==/com.example.ddd-o9yTi7O1l3Cm3EhqTvf2Rw==; Retain data and using new Line 8551: 02-02 05:12:10.808 1132 1228 I PackageManager: Update system package com.example.ddd resource path from /system/operator/app/AndroidDemoV1.0.apk to /data/app/~~IYd549AfrGeHUc-lWfY8kg==/com.example.ddd-o9yTi7O1l3Cm3EhqTvf2Rw==; Retain data and using new Line 8551: 02-02 05:12:10.808 1132 1228 I PackageManager: Update system package com.example.ddd resource path from /system/operator/app/AndroidDemoV1.0.apk to /data/app/~~IYd549AfrGeHUc-lWfY8kg==/com.example.ddd-o9yTi7O1l3Cm3EhqTvf2Rw==; Retain data and using new
总结:
系统apk发生更新时,系统依次发送广播:action: android.intent.action.PACKAGE_REMOVED、action: android.intent.action.PACKAGE_ADDED、action: android.intent.action.PACKAGE_REPLACED
且 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) 获取的值为true
Android 监听多用户切换,隐藏和禁用指定Apk
IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_ADDED); BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (userId == UserHandle.USER_NULL) { Slog.e("PMSdddd", "received an invalid EXTRA_USER_HANDLE"); return; } if (Intent.ACTION_USER_SWITCHED.equals(action) && userId > 0) { Slog.d("PMSdddd", "User switched to userId " + userId); AsyncTask.execute(new Runnable() { @Override public void run() { Slog.d("PMSdddd", "install start11"); Sbbbbbbbbbbb.hideOtherBrandAppWhenUserSwitched(); } }); } else if (Intent.ACTION_USER_ADDED.equals(action) && userId > 0) { Slog.d("PMSdddd", "Added User userId " + userId); AsyncTask.execute(new Runnable() { @Override public void run() { Slog.d("PMSdddd", "install start11");
Sbbbbbbbbbbb
.hideOtherBrandAppWhenUserSwitched(); } }); } } }; mContext.registerReceiver(mUserSwitchedReceiver, filter);
是否隐藏和禁用apk
/** * only hide app but don't delete user data * * @param pkgName */ private void hide(String pkgName) { final PackageManager pm = mContext.getPackageManager(); int userId = ActivityManager.getCurrentUser(); pm.setApplicationHiddenSettingAsUser(pkgName, true, new UserHandle(userId)); disableApplication(pkgName); } private void unhide(String pkgName) { final PackageManager pm = mContext.getPackageManager(); int userId = ActivityManager.getCurrentUser(); pm.setApplicationHiddenSettingAsUser(pkgName, false, new UserHandle(userId)); enableApplication(pkgName); } private void disableApplication(String pkgName) { final PackageManager pm = mContext.getPackageManager(); try { int state = pm.getApplicationEnabledSetting(pkgName); Slog.d(TAG, "disableApplication state: " + state + " pkgName:" + pkgName); if (state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) return; pm.setApplicationEnabledSetting(pkgName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0); } catch (IllegalArgumentException exeption) { Slog.w(TAG, "disableApplication error:" + exeption.getMessage()); } } private void enableApplication(String pkgName) { final PackageManager pm = mContext.getPackageManager(); try { int state = pm.getApplicationEnabledSetting(pkgName); Slog.d(TAG, "enableApplication state: " + state + " pkgName:" + pkgName); if (state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) return; pm.setApplicationEnabledSetting(pkgName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); } catch (IllegalArgumentException exeption) { Slog.w(TAG, "enableApplication error:" + exeption.getMessage()); } }
隐藏的apk或disable的apk,信息保存在 /data/system/users/0/package-restrictions.xml 文件内
<pkg name="com.google.android.apps.maps" ceDataInode="4439" enabled="3" enabledCaller="com.android.settings" domainVerificationStatus="2" app-link-generation="4"> <pkg name="com.google.android.apps.maps" ceDataInode="4439" enabled="2" enabledCaller="android" domainVerificationStatus="2" app-link-generation="4">
<pkg name="com.amazon.appmanager" ceDataInode="4472" hidden="true" enabled="2" enabledCaller="android" />
<pkg name="com.google.android.apps.maps" ceDataInode="4439" enabled="3" enabledCaller="com.android.settings" domainVerificationStatus="2" app-link-generation="4">
apk被hide后,保存的信息:hidden="true"
apk被disable后,根据 setApplicationEnabledSetting 传入的常量参数不同,enabled= 的值就会不同,如下介绍:
public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // disable应用时,若传入此参数,则应用在桌面没有图标,且在设置界面、应用程序列表里面也没有图标 (应用完全隐藏了)
public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // disable应用时,若传入此参数,则应用在桌面没有图标,但是在设置界面、应用程序列表里面有图标 (只是桌面图标隐藏了,设置里面仍可以看到图标,用户可以再次enable此应用)
另外:adb shell pm disable-user 应用包名: 相当于传入的参数是 COMPONENT_ENABLED_STATE_DISABLED。
查看手机有哪些应用处于disable状态的方法:
方法1:adb shell pm list packages -d
C:\Users\zzz>adb shell pm list packages -d
package:com.facebook.services
package:com.google.android.videos
package:com.facebook.appmanager
方法2:adb shell pm dump packages > Desktop/log2.txt
enabled=2 ---->表示应用处于disable状态,对应的值:COMPONENT_ENABLED_STATE_DISABLED
Package [com.facebook.appmanager] (a926214): userId=10098 pkg=Package{9ae0abd com.facebook.appmanager} codePath=/system/app/appmanager resourcePath=/system/app/appmanager legacyNativeLibraryDir=/system/app/appmanager/lib primaryCpuAbi=arm64-v8a secondaryCpuAbi=null versionCode=277606887 minSdk=21 targetSdk=30 versionName=67.3.0 splits=[base] apkSigningVersion=2 applicationInfo=ApplicationInfo{9ae0abd com.facebook.appmanager} flags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA ] privateFlags=[ PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION ALLOW_AUDIO_PLAYBACK_CAPTURE HAS_DOMAIN_URLS PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING ] forceQueryable=false queriesIntents=[Intent { act=com.facebook.secure.packagefinder.intent.ACTION_QUERY_PACKAGES }] dataDir=/data/user/0/com.facebook.appmanager supportsScreens=[small, medium, large, xlarge, resizeable, anyDensity] timeStamp=2021-07-12 23:30:37 firstInstallTime=2021-07-12 23:30:37 lastUpdateTime=2021-07-12 23:30:37 signatures=PackageSignatures{18e58b2 version:2, signatures:[c4e416cc], past signatures:[]} installPermissionsFixed=true pkgFlags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA ] declared permissions: com.facebook.appmanager.ACCESS: prot=signature, INSTALLED com.facebook.appmanager.API_ACCESS: prot=normal, INSTALLED install permissions: android.permission.DOWNLOAD_WITHOUT_NOTIFICATION: granted=true android.permission.FOREGROUND_SERVICE: granted=true android.permission.RECEIVE_BOOT_COMPLETED: granted=true android.permission.INTERNET: granted=true android.permission.GET_PACKAGE_SIZE: granted=true com.facebook.appmanager.ACCESS: granted=true android.permission.ACCESS_NETWORK_STATE: granted=true android.permission.ACCESS_WIFI_STATE: granted=true android.permission.WAKE_LOCK: granted=true User 0: ceDataInode=4785 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=2 instant=false virtual=false overlay paths: /product/overlay/NavigationBarModeGestural/NavigationBarModeGesturalOverlay.apk lastDisabledCaller: android gids=[3003]
查看哪些应用属于系统签名?
方法:adb shell pm dump packages > Desktop/log2.txt
包名为"android"的apk属于平台apk,肯定是系统签名,首先看一下包名为"android"的apk的签名信息:
Package [android] (ad28bfa): userId=1000 sharedUser=SharedUserSetting{769a3df android.uid.system/1000} pkg=Package{6103b22 android} codePath=/system/framework/framework-res.apk resourcePath=/system/framework/framework-res.apk legacyNativeLibraryDir=/system/lib64/framework-res primaryCpuAbi=arm64-v8a secondaryCpuAbi=null versionCode=30 minSdk=30 targetSdk=30 versionName=11 splits=[base] apkSigningVersion=3 applicationInfo=ApplicationInfo{6103b22 android} flags=[ SYSTEM PERSISTENT ALLOW_BACKUP ] privateFlags=[ PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION ALLOW_AUDIO_PLAYBACK_CAPTURE DEFAULT_TO_DEVICE_PROTECTED_STORAGE DIRECT_BOOT_AWARE PRIVILEGED PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING ] forceQueryable=true queriesPackages=[] dataDir=/data/system supportsScreens=[small, medium, large, xlarge, resizeable, anyDensity] timeStamp=2021-07-12 23:27:41 firstInstallTime=2021-07-12 23:27:41 lastUpdateTime=2021-07-12 23:27:41 signatures=PackageSignatures{539b9b3 version:3, signatures:[a0521abc], past signatures:[]} installPermissionsFixed=true pkgFlags=[ SYSTEM PERSISTENT ALLOW_BACKUP ] declared permissions: android.permission.READ_CONTACTS: prot=dangerous, INSTALLED android.permission.WRITE_CONTACTS: prot=dangerous, INSTALLED ........ User 0: ceDataInode=4316 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=0 instant=false virtual=false overlay paths: /product/overlay/NavigationBarModeGestural/NavigationBarModeGesturalOverlay.apk
从上面信息可以看到,签名信息:signatures:[a0521abc] ,然后在 log2.txt 文件全局搜索“a0521abc”,可以列出所有系统签名的应用
xref: /frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
case "enable": return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); case "disable": return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); case "disable-user": return runSetEnabledSetting( PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER); case "disable-until-used": return runSetEnabledSetting( PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); case "default-state": return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); case "hide": return runSetHiddenSetting(true); case "unhide": return runSetHiddenSetting(false);
xref: /frameworks/base/core/java/android/content/pm/PackageManager.java
/** @hide */ @IntDef(prefix = { "COMPONENT_ENABLED_STATE_" }, value = { COMPONENT_ENABLED_STATE_DEFAULT, COMPONENT_ENABLED_STATE_ENABLED, COMPONENT_ENABLED_STATE_DISABLED, COMPONENT_ENABLED_STATE_DISABLED_USER, COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, }) @Retention(RetentionPolicy.SOURCE) public @interface EnabledState {} /** * Flag for {@link #setApplicationEnabledSetting(String, int, int)} and * {@link #setComponentEnabledSetting(ComponentName, int, int)}: This * component or application is in its default enabled state (as specified in * its manifest). * <p> * Explicitly setting the component state to this value restores it's * enabled state to whatever is set in the manifest. */ public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; /** * Flag for {@link #setApplicationEnabledSetting(String, int, int)} * and {@link #setComponentEnabledSetting(ComponentName, int, int)}: This * component or application has been explictily enabled, regardless of * what it has specified in its manifest. */ public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; /** * Flag for {@link #setApplicationEnabledSetting(String, int, int)} * and {@link #setComponentEnabledSetting(ComponentName, int, int)}: This * component or application has been explicitly disabled, regardless of * what it has specified in its manifest. */ public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; /** * Flag for {@link #setApplicationEnabledSetting(String, int, int)} only: The * user has explicitly disabled the application, regardless of what it has * specified in its manifest. Because this is due to the user's request, * they may re-enable it if desired through the appropriate system UI. This * option currently <strong>cannot</strong> be used with * {@link #setComponentEnabledSetting(ComponentName, int, int)}. */ public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; /** * Flag for {@link #setApplicationEnabledSetting(String, int, int)} only: This * application should be considered, until the point where the user actually * wants to use it. This means that it will not normally show up to the user * (such as in the launcher), but various parts of the user interface can * use {@link #GET_DISABLED_UNTIL_USED_COMPONENTS} to still see it and allow * the user to select it (as for example an IME, device admin, etc). Such code, * once the user has selected the app, should at that point also make it enabled. * This option currently <strong>can not</strong> be used with * {@link #setComponentEnabledSetting(ComponentName, int, int)}. */ public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4;
开机默认禁用某个应用
1、pms的systemReady()方法内延迟2秒调用 // avoid issue: "java.lang.IllegalStateException: Cannot broadcast before boot completed" when hide or unhide app mHandler.postDelayed(new Runnable() { @Override public void run() { // isFirstBoot() 首次开机; isDeviceUpgrading() OTA升级首次开机 // 打印log if(isFirstBoot() && 其他判断条件){ //打印log disableApplication("目标应用包名",true); } } }, 2 * 1000); 2. 禁用和启用方法 private void disableApplication(String pkgName, boolean userDisable) { final PackageManager pm = mContext.getPackageManager(); try { int state = pm.getApplicationEnabledSetting(pkgName); Slog.d(TAG, "disableApplication state: " + state + " pkgName:" + pkgName + " defaultDisable:" + userDisable); if (userDisable) { int userId = ActivityManager.getCurrentUser(); pm.setApplicationHiddenSettingAsUser(pkgName, false, new UserHandle(userId)); // unhide apk if (state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) return; pm.setApplicationEnabledSetting(pkgName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0); // fake user disable } else { int userId = ActivityManager.getCurrentUser(); pm.setApplicationHiddenSettingAsUser(pkgName, true, new UserHandle(userId)); // hide apk if (state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) return; pm.setApplicationEnabledSetting(pkgName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0); // disable apk } } catch (IllegalArgumentException exeption) { Slog.w(TAG, "disableApplication error:" + exeption.getMessage()); } } private void enableApplication(String pkgName) { final PackageManager pm = mContext.getPackageManager(); try { int state = pm.getApplicationEnabledSetting(pkgName); Slog.d(TAG, "enableApplication state: " + state + " pkgName:" + pkgName); if (state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) return; pm.setApplicationEnabledSetting(pkgName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); } catch (IllegalArgumentException exeption) { Slog.w(TAG, "enableApplication error:" + exeption.getMessage()); } }
卸载apk但保留user data数据
调用平台自带的 setApplicationHiddenSettingAsUser 接口
private void hide(String pkgName) { final PackageManager pm = mContext.getPackageManager(); pm.setApplicationHiddenSettingAsUser(pkgName, true, UserHandle.SYSTEM); }
private void unhide(String pkgName) { final PackageManager pm = mContext.getPackageManager(); pm.setApplicationHiddenSettingAsUser(pkgName, false, UserHandle.SYSTEM); } |
/** * Puts the package in a hidden state, which is almost like an uninstalled state, * making the package unavailable, but it doesn't remove the data or the actual * package file. Application can be unhidden by either resetting the hidden state * or by installing it, such as with {@link #installExistingPackage(String)} * @hide */ @UnsupportedAppUsage public abstract boolean setApplicationHiddenSettingAsUser(@NonNull String packageName, boolean hidden, @NonNull UserHandle userHandle); |