android 通过action启动Activity拦截,Activity应用组件添加intent-filter priority(优先级)不生效
1. 项目背景
android 通过action启动Activity拦截,Activity应用组件添加intent-filter priority(优先级)不生效。
【前置条件】1.电源模式D1
【操作步骤】1.打开搜狐App的八方电台点击进行麦克风授权
【预期结果】1.正常跳转到车机定制的系统设置
【实际结果】1.跳转到Android原生设置页面
【发生概率】5/5
2. 分析过程
搜狐用的是安卓标准跳转方法
系统的应用程序设置页 ACTION_APPLICATION_DETAILS_SETTINGS = “android.settings.APPLICATION_DETAILS_SETTINGS”;
很明显是车机定制的设置App没有接收这个action,只有原生的设置接收这个action,所以导致跳转错误。
通过命令:adb shell dumpsys package > package.log
可以很清晰的看到,确实接收这个action的只有一个activity。
在 Activity 的 intent-filter 中,android:priority 主要影响 隐式 Intent 的匹配优先级。
当多个 Activity 声明了相同的 intent-filter 时,优先级 (priority) 较高的 Activity 更有可能被系统选中。
- android:priority 仅影响隐式 Intent(Implicit Intent),不影响显式 Intent(Explicit Intent)。
- android:priority 取值范围为 -1000 到 1000。
- 默认值为 0,即如果未设置 android:priority,默认是 0。
根据资料,我们进行如下方式修改:
修改完之后,通过adb install的方式,替换apk之后,发现并不能实现activity跳转拦截,dump如下:
通过上面的dump可以看出来,adb install替换app的方式,PMS里面的控件已经发生了变化,但是为什么功能却不生效呢?通过跟踪priority的代码可知,intent-filter的priority会通过IntentFilter.setPriority进行修改,详情
/**
* Modify priority of this filter. This only affects receiver filters.
* The priority of activity filters are set in XML and cannot be changed
* programmatically. The default priority is 0. Positive values will be
* before the default, lower values will be after it. Applications should
* use a value that is larger than {@link #SYSTEM_LOW_PRIORITY} and
* smaller than {@link #SYSTEM_HIGH_PRIORITY} .
*
* @param priority The new priority value.
*
* @see #getPriority
* @see #SYSTEM_LOW_PRIORITY
* @see #SYSTEM_HIGH_PRIORITY
*/
public final void setPriority(int priority) {
Log.w(TAG, "setPriority, this =" + this + ", priority = " + priority);
for (String action : mActions) {
Log.w(TAG, "-----setPriority, this =" + this + ", priority = " + priority + ", action = " + action);
if (action != null && action.contains("APPLICATION_DETAILS_SETTINGS")) {
Log.w(TAG, "setPriority, this =" + this + ", callstack = ", new Throwable("xxx"));
}
}
mPriority = priority;
}
01-01 12:32:56.797 1702 1755 W IntentFilter: -----setPriority, this =android.content.IntentFilter@94037f2, priority = 0, action = android.settings.APPLICATION_DETAILS_SETTINGS
01-01 12:32:56.797 1702 1755 W IntentFilter: setPriority, this =android.content.IntentFilter@94037f2, callstack =
01-01 12:32:56.797 1702 1755 W IntentFilter: java.lang.Throwable: xxx
01-01 12:32:56.797 1702 1755 W IntentFilter: at android.content.IntentFilter.setPriority(IntentFilter.java:534)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.resolution.ComponentResolver.adjustPriority(ComponentResolver.java:630)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.resolution.ComponentResolver.addAllComponents(ComponentResolver.java:209)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.InstallPackageHelper.commitPackageSettings(InstallPackageHelper.java:506)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.InstallPackageHelper.commitReconciledScanResultLocked(InstallPackageHelper.java:402)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.InstallPackageHelper.commitPackagesLocked(InstallPackageHelper.java:2020)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.InstallPackageHelper.installPackagesLI(InstallPackageHelper.java:1037)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.InstallPackageHelper.installPackagesTracedLI(InstallPackageHelper.java:921)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.InstallPackageHelper.processInstallRequests(InstallPackageHelper.java:861)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.InstallParams.lambda$processInstallRequestsAsync$0$com-android-server-pm-InstallParams(InstallParams.java:442)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.pm.InstallParams$$ExternalSyntheticLambda0.run(Unknown Source:6)
01-01 12:32:56.797 1702 1755 W IntentFilter: at android.os.Handler.handleCallback(Handler.java:942)
01-01 12:32:56.797 1702 1755 W IntentFilter: at android.os.Handler.dispatchMessage(Handler.java:99)
01-01 12:32:56.797 1702 1755 W IntentFilter: at android.os.Looper.loopOnce(Looper.java:201)
01-01 12:32:56.797 1702 1755 W IntentFilter: at android.os.Looper.loop(Looper.java:288)
01-01 12:32:56.797 1702 1755 W IntentFilter: at android.os.HandlerThread.run(HandlerThread.java:67)
01-01 12:32:56.797 1702 1755 W IntentFilter: at com.android.server.ServiceThread.run(ServiceThread.java:44)
通过堆栈信息,可知在install app的时候,会走进adjustPriority进行优先级的调整,并将priority设置成0,所以出现上述的不生效的情况。
/**
* Adjusts the priority of the given intent filter according to policy.
* <p>
* <ul>
* <li>The priority for non privileged applications is capped to '0'</li>
* <li>The priority for protected actions on privileged applications is capped to '0'</li>
* <li>The priority for unbundled updates to privileged applications is capped to the
* priority defined on the system partition</li>
* </ul>
* <p>
* <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
* allowed to obtain any priority on any action.
*/
private void adjustPriority(@NonNull Computer computer, List<ParsedActivity> systemActivities,
ParsedActivity activity, ParsedIntentInfo intentInfo, String setupWizardPackage) {
// nothing to do; priority is fine as-is
IntentFilter intentFilter = intentInfo.getIntentFilter();
if (intentFilter.getPriority() <= 0) {
return;
}
String packageName = activity.getPackageName();
AndroidPackage pkg = computer.getPackage(packageName);
final boolean privilegedApp = pkg.isPrivileged();
String className = activity.getClassName();
if (!privilegedApp) {
// non-privileged applications can never define a priority >0
if (DEBUG_FILTERS) {
Slog.i(TAG, "Non-privileged app; cap priority to 0;"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
intentFilter.setPriority(0);
return;
}
if (isProtectedAction(intentFilter)) {
if (mDeferProtectedFilters) {
// We can't deal with these just yet. No component should ever obtain a
// >0 priority for a protected actions, with ONE exception -- the setup
// wizard. The setup wizard, however, cannot be known until we're able to
// query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
// until all intent filters have been processed. Chicken, meet egg.
// Let the filter temporarily have a high priority and rectify the
// priorities after all system packages have been scanned.
if (mProtectedFilters == null) {
mProtectedFilters = new ArrayList<>();
}
mProtectedFilters.add(Pair.create(activity, intentInfo));
if (DEBUG_FILTERS) {
Slog.i(TAG, "Protected action; save for later;"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
} else {
if (DEBUG_FILTERS && setupWizardPackage == null) {
Slog.i(TAG, "No setup wizard;"
+ " All protected intents capped to priority 0");
}
if (packageName.equals(setupWizardPackage)) {
if (DEBUG_FILTERS) {
Slog.i(TAG, "Found setup wizard;"
+ " allow priority " + intentFilter.getPriority() + ";"
+ " package: " + packageName
+ " activity: " + className
+ " priority: " + intentFilter.getPriority());
}
// setup wizard gets whatever it wants
return;
}
if (DEBUG_FILTERS) {
Slog.i(TAG, "Protected action; cap priority to 0;"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
intentFilter.setPriority(0);
}
return;
}
if (systemActivities == null) {
// the system package is not disabled; we're parsing the system partition
// privileged apps on the system image get whatever priority they request
return;
}
// privileged app unbundled update ... try to find the same activity
ParsedActivity foundActivity = findMatchingActivity(systemActivities, activity);
if (foundActivity == null) {
// this is a new activity; it cannot obtain >0 priority
if (DEBUG_FILTERS) {
Slog.i(TAG, "New activity; cap priority to 0;"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
intentFilter.setPriority(0);
return;
}
// found activity, now check for filter equivalence
// a shallow copy is enough; we modify the list, not its contents
final List<ParsedIntentInfo> intentListCopy =
new ArrayList<>(foundActivity.getIntents());
// find matching action subsets
final Iterator<String> actionsIterator = intentFilter.actionsIterator();
if (actionsIterator != null) {
getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator);
if (intentListCopy.size() == 0) {
// no more intents to match; we're not equivalent
if (DEBUG_FILTERS) {
Slog.i(TAG, "Mismatched action; cap priority to 0;"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
intentFilter.setPriority(0);
return;
}
}
// find matching category subsets
final Iterator<String> categoriesIterator = intentFilter.categoriesIterator();
if (categoriesIterator != null) {
getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator,
categoriesIterator);
if (intentListCopy.size() == 0) {
// no more intents to match; we're not equivalent
if (DEBUG_FILTERS) {
Slog.i(TAG, "Mismatched category; cap priority to 0;"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
intentFilter.setPriority(0);
return;
}
}
// find matching schemes subsets
final Iterator<String> schemesIterator = intentFilter.schemesIterator();
if (schemesIterator != null) {
getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator);
if (intentListCopy.size() == 0) {
// no more intents to match; we're not equivalent
if (DEBUG_FILTERS) {
Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
intentFilter.setPriority(0);
return;
}
}
// find matching authorities subsets
final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator =
intentFilter.authoritiesIterator();
if (authoritiesIterator != null) {
getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator,
authoritiesIterator);
if (intentListCopy.size() == 0) {
// no more intents to match; we're not equivalent
if (DEBUG_FILTERS) {
Slog.i(TAG, "Mismatched authority; cap priority to 0;"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
intentFilter.setPriority(0);
return;
}
}
// we found matching filter(s); app gets the max priority of all intents
int cappedPriority = 0;
for (int i = intentListCopy.size() - 1; i >= 0; --i) {
cappedPriority = Math.max(cappedPriority,
intentListCopy.get(i).getIntentFilter().getPriority());
}
if (intentFilter.getPriority() > cappedPriority) {
if (DEBUG_FILTERS) {
Slog.i(TAG, "Found matching filter(s);"
+ " cap priority to " + cappedPriority + ";"
+ " package: " + packageName
+ " activity: " + className
+ " origPrio: " + intentFilter.getPriority());
}
intentFilter.setPriority(cappedPriority);
return;
}
// all this for nothing; the requested priority was <= what was on the system
}
通过代码可知,以下几种情况不生效:
- 内置到/system/app 不生效
- 手动安装方式新增action的情况不生效
最后通过push的方式替换apk,验证OK,问题解决。
3. 修改方案以及注意事项
测试过的几种上不生效的情况
- 内置到/system/app 不生效
- 手动安装方式新增action的情况不生效