diff options
9 files changed, 112 insertions, 15 deletions
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index ee988781e51d..236f8507c0a0 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -415,6 +415,12 @@ public final class SystemUiDeviceConfigFlags { public static final String CHOOSER_TARGET_RANKING_ENABLED = "chooser_target_ranking_enabled"; /** + * (boolean) Whether dark launch of remote prediction service is enabled. + */ + public static final String DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED = + "dark_launch_remote_prediction_service_enabled"; + + /** * (boolean) Whether to enable pinch resizing for PIP. */ public static final String PIP_PINCH_RESIZE = "pip_pinch_resize"; diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java index e9a099ae43a9..2c5038940e98 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java @@ -35,6 +35,7 @@ import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.Binder; import android.os.IBinder; +import android.os.Process; import android.os.ResultReceiver; import android.os.ShellCallback; import android.util.Slog; @@ -179,7 +180,8 @@ public class AppPredictionManagerService extends Context ctx = getContext(); if (!(ctx.checkCallingPermission(PACKAGE_USAGE_STATS) == PERMISSION_GRANTED || mServiceNameResolver.isTemporary(userId) - || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) { + || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()) + || Binder.getCallingUid() == Process.SYSTEM_UID)) { String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java index 735f420ca03e..cd332a68fa88 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java @@ -40,6 +40,7 @@ import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.infra.AbstractRemoteService; import com.android.server.LocalServices; import com.android.server.infra.AbstractPerUserSystemService; @@ -55,6 +56,8 @@ public class AppPredictionPerUserService extends private static final String TAG = AppPredictionPerUserService.class.getSimpleName(); private static final String PREDICT_USING_PEOPLE_SERVICE_PREFIX = "predict_using_people_service_"; + private static final String REMOTE_APP_PREDICTOR_KEY = "remote_app_predictor"; + @Nullable @GuardedBy("mLock") @@ -112,8 +115,16 @@ public class AppPredictionPerUserService extends @GuardedBy("mLock") public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context, @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) { - final boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, + boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false); + if (context.getExtras() != null + && context.getExtras().getBoolean(REMOTE_APP_PREDICTOR_KEY, false) + && DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, false) + ) { + // connect with remote AppPredictionService instead for dark launch + usesPeopleService = false; + } final boolean serviceExists = resolveService(sessionId, false, usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId)); if (serviceExists && !mSessionInfos.containsKey(sessionId)) { diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java index e7d01219f6c1..eab3b770a94a 100644 --- a/services/people/java/com/android/server/people/PeopleService.java +++ b/services/people/java/com/android/server/people/PeopleService.java @@ -388,9 +388,11 @@ public class PeopleService extends SystemService { private Map<AppPredictionSessionId, SessionInfo> mSessions = new ArrayMap<>(); @Override - public void onCreatePredictionSession(AppPredictionContext context, + public void onCreatePredictionSession(AppPredictionContext appPredictionContext, AppPredictionSessionId sessionId) { - mSessions.put(sessionId, new SessionInfo(context, mDataManager, sessionId.getUserId())); + mSessions.put(sessionId, + new SessionInfo(appPredictionContext, mDataManager, sessionId.getUserId(), + getContext())); } @Override diff --git a/services/people/java/com/android/server/people/SessionInfo.java b/services/people/java/com/android/server/people/SessionInfo.java index 28612f1dd49b..d256d9c24540 100644 --- a/services/people/java/com/android/server/people/SessionInfo.java +++ b/services/people/java/com/android/server/people/SessionInfo.java @@ -20,6 +20,7 @@ import android.annotation.UserIdInt; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppTarget; import android.app.prediction.IPredictionCallback; +import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -40,9 +41,9 @@ class SessionInfo { new RemoteCallbackList<>(); SessionInfo(AppPredictionContext predictionContext, DataManager dataManager, - @UserIdInt int callingUserId) { + @UserIdInt int callingUserId, Context context) { mAppTargetPredictor = AppTargetPredictor.create(predictionContext, - this::updatePredictions, dataManager, callingUserId); + this::updatePredictions, dataManager, callingUserId, context); } void addCallback(IPredictionCallback callback) { diff --git a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java index c89dadc3fbd6..e19108198bb7 100644 --- a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java +++ b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java @@ -24,6 +24,7 @@ import android.app.prediction.AppPredictionContext; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; +import android.content.Context; import com.android.internal.annotations.VisibleForTesting; import com.android.server.people.data.DataManager; @@ -43,10 +44,10 @@ public class AppTargetPredictor { /** Creates a {@link AppTargetPredictor} instance based on the prediction context. */ public static AppTargetPredictor create(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, - @NonNull DataManager dataManager, @UserIdInt int callingUserId) { + @NonNull DataManager dataManager, @UserIdInt int callingUserId, Context context) { if (UI_SURFACE_SHARE.equals(predictionContext.getUiSurface())) { - return new ShareTargetPredictor( - predictionContext, updatePredictionsMethod, dataManager, callingUserId); + return new ShareTargetPredictor(predictionContext, updatePredictionsMethod, dataManager, + callingUserId, context); } return new AppTargetPredictor( predictionContext, updatePredictionsMethod, dataManager, callingUserId); @@ -124,6 +125,11 @@ public class AppTargetPredictor { callback.accept(targets); } + /** To be overridden by the subclass to recycle resources. */ + @WorkerThread + void destroy() { + } + AppPredictionContext getPredictionContext() { return mPredictionContext; } diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java index 236ac8407faa..368b737d2133 100644 --- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java +++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java @@ -16,6 +16,8 @@ package com.android.server.people.prediction; +import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; + import static java.util.Collections.reverseOrder; import android.annotation.NonNull; @@ -23,17 +25,23 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.prediction.AppPredictionContext; +import android.app.prediction.AppPredictionManager; +import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; +import android.content.Context; import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; +import android.os.UserHandle; +import android.provider.DeviceConfig; import android.util.Log; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ChooserActivity; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.server.people.data.ConversationInfo; import com.android.server.people.data.DataManager; import com.android.server.people.data.EventHistory; @@ -52,14 +60,27 @@ class ShareTargetPredictor extends AppTargetPredictor { private static final String TAG = "ShareTargetPredictor"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final String REMOTE_APP_PREDICTOR_KEY = "remote_app_predictor"; private final IntentFilter mIntentFilter; + private final AppPredictor mRemoteAppPredictor; ShareTargetPredictor(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, - @NonNull DataManager dataManager, @UserIdInt int callingUserId) { + @NonNull DataManager dataManager, + @UserIdInt int callingUserId, @NonNull Context context) { super(predictionContext, updatePredictionsMethod, dataManager, callingUserId); mIntentFilter = predictionContext.getExtras().getParcelable( ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY); + if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, + false)) { + predictionContext.getExtras().putBoolean(REMOTE_APP_PREDICTOR_KEY, true); + mRemoteAppPredictor = context.createContextAsUser(UserHandle.of(callingUserId), 0) + .getSystemService(AppPredictionManager.class) + .createAppPredictionSession(predictionContext); + } else { + mRemoteAppPredictor = null; + } } /** Reports chosen history of direct/app share targets. */ @@ -72,6 +93,9 @@ class ShareTargetPredictor extends AppTargetPredictor { if (mIntentFilter != null) { getDataManager().reportShareTargetEvent(event, mIntentFilter); } + if (mRemoteAppPredictor != null) { + mRemoteAppPredictor.notifyAppTargetEvent(event); + } } /** Provides prediction on direct share targets */ @@ -129,6 +153,15 @@ class ShareTargetPredictor extends AppTargetPredictor { callback.accept(appTargetList); } + /** Recycles resources. */ + @WorkerThread + @Override + void destroy() { + if (mRemoteAppPredictor != null) { + mRemoteAppPredictor.destroy(); + } + } + private List<ShareTarget> getDirectShareTargets() { List<ShareTarget> shareTargets = new ArrayList<>(); List<ShareShortcutInfo> shareShortcuts = diff --git a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java index ecff409ccaf1..506624064265 100644 --- a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java @@ -47,12 +47,14 @@ import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.os.test.TestLooper; +import android.provider.DeviceConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.server.LocalServices; import org.junit.After; @@ -126,6 +128,10 @@ public final class PeopleServiceTest { .setPredictedTargetCount(APP_PREDICTION_TARGET_COUNT) .setExtras(new Bundle()) .build(); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, + Boolean.toString(false), + true /* makeDefault*/); } @After diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java index b09a3c374e86..fac5c1f94e56 100644 --- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java +++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java @@ -22,13 +22,17 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anySet; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.prediction.AppPredictionContext; +import android.app.prediction.AppPredictionManager; import android.app.prediction.AppTarget; +import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; import android.content.ComponentName; import android.content.Context; @@ -38,9 +42,11 @@ import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; import android.os.Bundle; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.util.Range; import com.android.internal.app.ChooserActivity; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.server.people.data.ConversationInfo; import com.android.server.people.data.DataManager; import com.android.server.people.data.EventHistory; @@ -71,6 +77,14 @@ public final class ShareTargetPredictorTest { private static final String PACKAGE_3 = "pkg3"; private static final String CLASS_1 = "cls1"; private static final String CLASS_2 = "cls2"; + private static final AppTargetEvent APP_TARGET_EVENT = + new AppTargetEvent.Builder( + new AppTarget.Builder( + new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)).build(), + AppTargetEvent.ACTION_LAUNCH) + .setLaunchLocation(ChooserActivity.LAUNCH_LOCATION_DIRECT_SHARE) + .build(); + private static final IntentFilter INTENT_FILTER = IntentFilter.create("SEND", "text/plain"); @Mock private Context mContext; @Mock private DataManager mDataManager; @@ -102,17 +116,33 @@ public final class ShareTargetPredictorTest { when(mDataManager.getShareShortcuts(any(), anyInt())).thenReturn(mShareShortcuts); when(mDataManager.getPackage(PACKAGE_1, USER_ID)).thenReturn(mPackageData1); when(mDataManager.getPackage(PACKAGE_2, USER_ID)).thenReturn(mPackageData2); + when(mContext.createContextAsUser(any(), any())).thenReturn(mContext); + when(mContext.getSystemServiceName(AppPredictionManager.class)).thenReturn( + Context.APP_PREDICTION_SERVICE); + when(mContext.getSystemService(AppPredictionManager.class)) + .thenReturn(new AppPredictionManager(mContext)); Bundle bundle = new Bundle(); - bundle.putObject(ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY, - IntentFilter.create("SEND", "text/plain")); + bundle.putObject(ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY, INTENT_FILTER); AppPredictionContext predictionContext = new AppPredictionContext.Builder(mContext) .setUiSurface(UI_SURFACE_SHARE) .setPredictedTargetCount(NUM_PREDICTED_TARGETS) .setExtras(bundle) .build(); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, + Boolean.toString(true), + true /* makeDefault*/); mPredictor = new ShareTargetPredictor( - predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID); + predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID, mContext); + } + + @Test + public void testReportAppTargetEvent() { + mPredictor.reportAppTargetEvent(APP_TARGET_EVENT); + + verify(mDataManager, times(1)) + .reportShareTargetEvent(eq(APP_TARGET_EVENT), eq(INTENT_FILTER)); } @Test @@ -240,7 +270,7 @@ public final class ShareTargetPredictorTest { .setExtras(new Bundle()) .build(); mPredictor = new ShareTargetPredictor( - predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID); + predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID, mContext); mPredictor.predictTargets(); @@ -349,7 +379,7 @@ public final class ShareTargetPredictorTest { .setExtras(new Bundle()) .build(); mPredictor = new ShareTargetPredictor( - predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID); + predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID, mContext); AppTarget appTarget1 = new AppTarget.Builder( new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)) .build(); |