Implement new API
This is the first swack at the new, 2-phase API. Adds the new methods
to the resolver service and makes the split name explicit on the
installer intent.
The 2nd phase will not yet be invoked; that's coming in a follow-on
change.
Bug: 25119046
Test: build & install the sample resolver and run 'adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://www.tripadvisor.com/Tourism-g33020-San_Jose_California-Vacations.html"'
Change-Id: I2df6fa64d46f17a86a2e32b19417632c594fb10f
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index e4ec169..2a0c6d0 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -458,9 +458,12 @@
// Instead, launch the ephemeral installer. Once the installer is finished, it
// starts either the intent we resolved here [on install error] or the ephemeral
// app [on install success].
- if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
+ if (rInfo != null && rInfo.ephemeralIntentInfo != null) {
+ final String packageName =
+ rInfo.ephemeralIntentInfo.getEphemeralResolveInfo().getPackageName();
+ final String splitName = rInfo.ephemeralIntentInfo.getSplitName();
intent = buildEphemeralInstallerIntent(intent, ephemeralIntent,
- rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType,
+ packageName, splitName, callingPackage, resolvedType,
userId);
resolvedType = null;
callingUid = realCallingUid;
@@ -524,7 +527,8 @@
* Builds and returns an intent to launch the ephemeral installer.
*/
private Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent,
- String ephemeralPackage, String callingPackage, String resolvedType, int userId) {
+ String ephemeralPackageName, String ephemeralSplitName, String callingPackage,
+ String resolvedType, int userId) {
final Intent nonEphemeralIntent = new Intent(origIntent);
nonEphemeralIntent.setFlags(nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
// Intent that is launched if the ephemeral package couldn't be installed
@@ -540,7 +544,7 @@
if (USE_DEFAULT_EPHEMERAL_LAUNCHER) {
// Force the intent to be directed to the ephemeral package
ephemeralIntent = new Intent(origIntent);
- ephemeralIntent.setPackage(ephemeralPackage);
+ ephemeralIntent.setPackage(ephemeralPackageName);
} else {
// Success intent goes back to the installer
ephemeralIntent = new Intent(launchIntent);
@@ -564,7 +568,8 @@
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NO_HISTORY
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackage);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackageName);
+ intent.putExtra(Intent.EXTRA_SPLIT_NAME, ephemeralSplitName);
intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget));
intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget));
// TODO: Remove when the platform has fully implemented ephemeral apps
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index a6a3774..9778919 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -51,6 +51,8 @@
private final Object mLock = new Object();
private final GetEphemeralResolveInfoCaller mGetEphemeralResolveInfoCaller =
new GetEphemeralResolveInfoCaller();
+ private final GetEphemeralIntentFilterCaller mGetEphemeralIntentFilterCaller =
+ new GetEphemeralIntentFilterCaller();
private final ServiceConnection mServiceConnection = new MyServiceConnection();
private final Context mContext;
/** Intent used to bind to the service */
@@ -64,12 +66,26 @@
mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName);
}
- public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(
- int hashPrefix[], int prefixMask) {
+ public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(int hashPrefix[]) {
throwIfCalledOnMainThread();
try {
return mGetEphemeralResolveInfoCaller.getEphemeralResolveInfoList(
- getRemoteInstanceLazy(), hashPrefix, prefixMask);
+ getRemoteInstanceLazy(), hashPrefix);
+ } catch (RemoteException re) {
+ } catch (TimeoutException te) {
+ } finally {
+ synchronized (mLock) {
+ mLock.notifyAll();
+ }
+ }
+ return null;
+ }
+
+ public final List<EphemeralResolveInfo> getEphemeralIntentFilterList(int digestPrefix[]) {
+ throwIfCalledOnMainThread();
+ try {
+ return mGetEphemeralIntentFilterCaller.getEphemeralIntentFilterList(
+ getRemoteInstanceLazy(), digestPrefix);
} catch (RemoteException re) {
} catch (TimeoutException te) {
} finally {
@@ -181,10 +197,38 @@
}
public List<EphemeralResolveInfo> getEphemeralResolveInfoList(
- IEphemeralResolver target, int hashPrefix[], int prefixMask)
+ IEphemeralResolver target, int hashPrefix[])
throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
- target.getEphemeralResolveInfoList(mCallback, hashPrefix, prefixMask, sequence);
+ target.getEphemeralResolveInfoList(mCallback, hashPrefix, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class GetEphemeralIntentFilterCaller
+ extends TimedRemoteCaller<List<EphemeralResolveInfo>> {
+ private final IRemoteCallback mCallback;
+
+ public GetEphemeralIntentFilterCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ final ArrayList<EphemeralResolveInfo> resolveList =
+ data.getParcelableArrayList(
+ EphemeralResolverService.EXTRA_RESOLVE_INFO);
+ int sequence =
+ data.getInt(EphemeralResolverService.EXTRA_SEQUENCE, -1);
+ onRemoteMethodResult(resolveList, sequence);
+ }
+ };
+ }
+
+ public List<EphemeralResolveInfo> getEphemeralIntentFilterList(
+ IEphemeralResolver target, int digestPrefix[])
+ throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.getEphemeralIntentFilterList(mCallback, digestPrefix, sequence);
return getResultTimed(sequence);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b1f2a24..21b6964 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -122,6 +122,7 @@
import android.content.pm.AppsQueryHelper;
import android.content.pm.ComponentInfo;
import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.EphemeralIntentFilter;
import android.content.pm.EphemeralResolveInfo;
import android.content.pm.EphemeralResolveInfo.EphemeralDigest;
import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
@@ -478,9 +479,6 @@
private static final String VENDOR_OVERLAY_THEME_PERSIST_PROPERTY
= "persist.vendor.overlay.theme";
- private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000;
- private static int DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT = 5;
-
/** Permission grant: not grant the permission. */
private static final int GRANT_DENIED = 1;
@@ -4945,19 +4943,15 @@
return true;
}
- private static EphemeralResolveInfo getEphemeralResolveInfo(
+ private static EphemeralResolveIntentInfo getEphemeralIntentInfo(
Context context, EphemeralResolverConnection resolverConnection, Intent intent,
String resolvedType, int userId, String packageName) {
- final int ephemeralPrefixMask = Global.getInt(context.getContentResolver(),
- Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK);
- final int ephemeralPrefixCount = Global.getInt(context.getContentResolver(),
- Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT);
- final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask,
- ephemeralPrefixCount);
+ final EphemeralDigest digest =
+ new EphemeralDigest(intent.getData().getHost(), 5 /*maxDigests*/);
final int[] shaPrefix = digest.getDigestPrefix();
final byte[][] digestBytes = digest.getDigestBytes();
final List<EphemeralResolveInfo> ephemeralResolveInfoList =
- resolverConnection.getEphemeralResolveInfoList(shaPrefix, ephemeralPrefixMask);
+ resolverConnection.getEphemeralResolveInfoList(shaPrefix);
if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
// No hash prefix match; there are no ephemeral apps for this domain.
return null;
@@ -4969,9 +4963,10 @@
if (!Arrays.equals(digestBytes[i], ephemeralApplication.getDigestBytes())) {
continue;
}
- final List<IntentFilter> filters = ephemeralApplication.getFilters();
+ final List<EphemeralIntentFilter> ephemeralFilters =
+ ephemeralApplication.getIntentFilters();
// No filters; this should never happen.
- if (filters.isEmpty()) {
+ if (ephemeralFilters.isEmpty()) {
continue;
}
if (packageName != null
@@ -4980,13 +4975,21 @@
}
// We have a domain match; resolve the filters to see if anything matches.
final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver();
- for (int j = filters.size() - 1; j >= 0; --j) {
- final EphemeralResolveIntentInfo intentInfo =
- new EphemeralResolveIntentInfo(filters.get(j), ephemeralApplication);
- ephemeralResolver.addFilter(intentInfo);
+ for (int j = ephemeralFilters.size() - 1; j >= 0; --j) {
+ final EphemeralIntentFilter ephemeralFilter = ephemeralFilters.get(j);
+ final List<IntentFilter> splitFilters = ephemeralFilter.getFilters();
+ if (splitFilters == null || splitFilters.isEmpty()) {
+ continue;
+ }
+ for (int k = splitFilters.size() - 1; k >= 0; --k) {
+ final EphemeralResolveIntentInfo intentInfo =
+ new EphemeralResolveIntentInfo(splitFilters.get(k),
+ ephemeralApplication, ephemeralFilter.getSplitName());
+ ephemeralResolver.addFilter(intentInfo);
+ }
}
- List<EphemeralResolveInfo> matchedResolveInfoList = ephemeralResolver.queryIntent(
- intent, resolvedType, false /*defaultOnly*/, userId);
+ List<EphemeralResolveIntentInfo> matchedResolveInfoList = ephemeralResolver
+ .queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
if (!matchedResolveInfoList.isEmpty()) {
return matchedResolveInfoList.get(0);
}
@@ -5469,15 +5472,15 @@
}
if (addEphemeral) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
- final EphemeralResolveInfo ai = getEphemeralResolveInfo(
+ final EphemeralResolveIntentInfo intentInfo = getEphemeralIntentInfo(
mContext, mEphemeralResolverConnection, intent, resolvedType, userId,
matchEphemeralPackage ? pkgName : null);
- if (ai != null) {
+ if (intentInfo != null) {
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo);
- ephemeralInstaller.ephemeralResolveInfo = ai;
+ ephemeralInstaller.ephemeralIntentInfo = intentInfo;
// make sure this resolver is the default
ephemeralInstaller.isDefault = true;
ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -11451,7 +11454,7 @@
}
private static final class EphemeralIntentResolver
- extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> {
+ extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveIntentInfo> {
/**
* The result that has the highest defined order. Ordering applies on a
* per-package basis. Mapping is from package name to Pair of order and
@@ -11476,7 +11479,7 @@
}
@Override
- protected EphemeralResolveInfo newResult(EphemeralResolveIntentInfo info, int match,
+ protected EphemeralResolveIntentInfo newResult(EphemeralResolveIntentInfo info, int match,
int userId) {
if (!sUserManager.exists(userId)) {
return null;
@@ -11494,18 +11497,18 @@
// non-zero order, enable ordering
mOrderResult.put(packageName, new Pair<>(order, res));
}
- return res;
+ return info;
}
@Override
- protected void filterResults(List<EphemeralResolveInfo> results) {
+ protected void filterResults(List<EphemeralResolveIntentInfo> results) {
// only do work if ordering is enabled [most of the time it won't be]
if (mOrderResult.size() == 0) {
return;
}
int resultSize = results.size();
for (int i = 0; i < resultSize; i++) {
- final EphemeralResolveInfo info = results.get(i);
+ final EphemeralResolveInfo info = results.get(i).getEphemeralResolveInfo();
final String packageName = info.getPackageName();
final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName);
if (savedInfo == null) {