Fix deadlock in ComponentAliasResolver

Test: atest ComponentAliasTests ComponentAliasTests1 ComponentAliasTests2
(except for existing flakiness: b/228613740)
Bug: 228273242

Change-Id: Iea7679702ce9c883e6df196de0ae47d7bdd5d876
This commit is contained in:
Makoto Onuki
2022-04-07 15:18:45 -07:00
parent dd99260942
commit 4d9f545a40
2 changed files with 32 additions and 16 deletions

View File

@@ -41,6 +41,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.compat.CompatChange;
import com.android.server.compat.PlatformCompat;
@@ -53,17 +54,23 @@ import java.util.function.Supplier;
/**
* Manages and handles component aliases, which is an experimental feature.
*
* For now, this is an experimental feature to evaluate feasibility, so the implementation is
* NOTE: THIS CLASS IS PURELY EXPERIMENTAL AND WILL BE REMOVED IN FUTURE ANDROID VERSIONS.
* DO NOT USE IT.
*
* "Component alias" allows an android manifest component (for now only broadcasts and services)
* to be defined in one android package while having the implementation in a different package.
*
* When/if this becomes a real feature, it will be most likely implemented very differently,
* which is why this shouldn't be used.
*
* For now, because this is an experimental feature to evaluate feasibility, the implementation is
* "quick & dirty". For example, to define aliases, we use a regular intent filter and meta-data
* in the manifest, instead of adding proper tags/attributes to AndroidManifest.xml.
*
* Because it's an experimental feature, it can't be enabled on a user build.
* This feature is disabled by default.
*
* Also, for now, aliases can be defined across any packages, but in the final version, there'll
* be restrictions:
* - We probably should only allow either privileged or preinstalled apps.
* - Aliases can only be defined across packages that are atomically installed, and signed with the
* same key.
* Also, for now, aliases can be defined across packages with different certificates, but
* in a final version this will most likely be tightened.
*/
public class ComponentAliasResolver {
private static final String TAG = "ComponentAliasResolver";
@@ -172,12 +179,17 @@ public class ComponentAliasResolver {
USE_EXPERIMENTAL_COMPONENT_ALIAS, "android", UserHandle.USER_SYSTEM));
if (enabled != mEnabled) {
Slog.i(TAG, (enabled ? "Enabling" : "Disabling") + " component aliases...");
if (enabled) {
mPackageMonitor.register(mAm.mContext, UserHandle.ALL,
/* externalStorage= */ false, BackgroundThread.getHandler());
} else {
mPackageMonitor.unregister();
}
FgThread.getHandler().post(() -> {
// Registering/unregistering a receiver internally takes the AM lock, but AM
// calls into this class while holding the AM lock. So do it on a handler to
// avoid deadlocks.
if (enabled) {
mPackageMonitor.register(mAm.mContext, UserHandle.ALL,
/* externalStorage= */ false, BackgroundThread.getHandler());
} else {
mPackageMonitor.unregister();
}
});
}
mEnabled = enabled;
mEnabledByDeviceConfig = enabledByDeviceConfig;

View File

@@ -46,11 +46,15 @@ public class BaseComponentAliasTest {
sDeviceConfig.set("enable_experimental_component_alias", "");
sDeviceConfig.set("component_alias_overrides", "");
// Make sure the feature is actually enabled.
// Make sure the feature is actually enabled, and the aliases are loaded.
TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
return ShellUtils.runShellCommand("dumpsys activity component-alias")
.indexOf("Enabled: true") > 0;
String out = ShellUtils.runShellCommand("dumpsys activity component-alias");
return out.contains("Enabled: true")
&& out.contains("android.content.componentalias.tests/.b.Alias04")
&& out.contains("android.content.componentalias.tests/.s.Alias04");
});
ShellUtils.runShellCommand("am wait-for-broadcast-idle");
}
@AfterClass