Merge "Stabalize AmbientContext detection by restoring client requests." into tm-dev am: 889d4894d9
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17893731 Change-Id: I3349b7d8d51695db910fb3437444e8a075d52bb0 Ignore-AOSP-First: this is an automerge Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -43,7 +43,6 @@ import android.os.RemoteException;
|
|||||||
import android.service.ambientcontext.AmbientContextDetectionResult;
|
import android.service.ambientcontext.AmbientContextDetectionResult;
|
||||||
import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
|
import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArraySet;
|
|
||||||
import android.util.IndentingPrintWriter;
|
import android.util.IndentingPrintWriter;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
@@ -54,7 +53,6 @@ import com.android.server.infra.AbstractPerUserSystemService;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Per-user manager service for {@link AmbientContextEvent}s.
|
* Per-user manager service for {@link AmbientContextEvent}s.
|
||||||
@@ -69,19 +67,13 @@ final class AmbientContextManagerPerUserService extends
|
|||||||
RemoteAmbientContextDetectionService mRemoteService;
|
RemoteAmbientContextDetectionService mRemoteService;
|
||||||
|
|
||||||
private ComponentName mComponentName;
|
private ComponentName mComponentName;
|
||||||
private Set<PendingIntent> mExistingPendingIntents;
|
|
||||||
|
|
||||||
AmbientContextManagerPerUserService(
|
AmbientContextManagerPerUserService(
|
||||||
@NonNull AmbientContextManagerService master, Object lock, @UserIdInt int userId) {
|
@NonNull AmbientContextManagerService master, Object lock, @UserIdInt int userId) {
|
||||||
super(master, lock, userId);
|
super(master, lock, userId);
|
||||||
mExistingPendingIntents = new ArraySet<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyLocked() {
|
void destroyLocked() {
|
||||||
if (isVerbose()) {
|
|
||||||
Slog.v(TAG, "destroyLocked()");
|
|
||||||
}
|
|
||||||
|
|
||||||
Slog.d(TAG, "Trying to cancel the remote request. Reason: Service destroyed.");
|
Slog.d(TAG, "Trying to cancel the remote request. Reason: Service destroyed.");
|
||||||
if (mRemoteService != null) {
|
if (mRemoteService != null) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
@@ -118,7 +110,19 @@ final class AmbientContextManagerPerUserService extends
|
|||||||
if (mComponentName == null) {
|
if (mComponentName == null) {
|
||||||
mComponentName = updateServiceInfoLocked();
|
mComponentName = updateServiceInfoLocked();
|
||||||
}
|
}
|
||||||
return mComponentName != null;
|
if (mComponentName == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceInfo serviceInfo;
|
||||||
|
try {
|
||||||
|
serviceInfo = AppGlobals.getPackageManager().getServiceInfo(
|
||||||
|
mComponentName, 0, mUserId);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.w(TAG, "RemoteException while setting up service");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return serviceInfo != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -171,18 +175,10 @@ final class AmbientContextManagerPerUserService extends
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any existing PendingIntent for this package.
|
// Register package and add to existing ClientRequests cache
|
||||||
String callingPackage = pendingIntent.getCreatorPackage();
|
startDetection(request, pendingIntent.getCreatorPackage(),
|
||||||
PendingIntent duplicatePendingIntent = findExistingRequestByPackage(callingPackage);
|
createDetectionResultRemoteCallback(), clientStatusCallback);
|
||||||
if (duplicatePendingIntent != null) {
|
mMaster.newClientAdded(mUserId, request, pendingIntent, clientStatusCallback);
|
||||||
Slog.d(TAG, "Replace duplicate request from " + callingPackage);
|
|
||||||
mExistingPendingIntents.remove(duplicatePendingIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register package and add pendingIntent to mExistingPendingIntents
|
|
||||||
startDetection(request, callingPackage, createDetectionResultRemoteCallback(),
|
|
||||||
getServerStatusCallback(clientStatusCallback));
|
|
||||||
mExistingPendingIntents.add(pendingIntent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,15 +210,17 @@ final class AmbientContextManagerPerUserService extends
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void startDetection(AmbientContextEventRequest request, String callingPackage,
|
void startDetection(AmbientContextEventRequest request, String callingPackage,
|
||||||
RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
|
RemoteCallback detectionResultCallback, RemoteCallback clientStatusCallback) {
|
||||||
Slog.d(TAG, "Requested detection of " + request.getEventTypes());
|
Slog.d(TAG, "Requested detection of " + request.getEventTypes());
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (setUpServiceIfNeeded()) {
|
if (setUpServiceIfNeeded()) {
|
||||||
ensureRemoteServiceInitiated();
|
ensureRemoteServiceInitiated();
|
||||||
mRemoteService.startDetection(request, callingPackage, detectionResultCallback,
|
mRemoteService.startDetection(request, callingPackage, detectionResultCallback,
|
||||||
statusCallback);
|
getServerStatusCallback(clientStatusCallback));
|
||||||
} else {
|
} else {
|
||||||
Slog.w(TAG, "No valid component found for AmbientContextDetectionService");
|
Slog.w(TAG, "No valid component found for AmbientContextDetectionService");
|
||||||
|
sendStatusToCallback(clientStatusCallback,
|
||||||
|
AmbientContextManager.STATUS_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,15 +243,8 @@ final class AmbientContextManagerPerUserService extends
|
|||||||
*/
|
*/
|
||||||
public void onUnregisterObserver(String callingPackage) {
|
public void onUnregisterObserver(String callingPackage) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
PendingIntent pendingIntent = findExistingRequestByPackage(callingPackage);
|
stopDetection(callingPackage);
|
||||||
if (pendingIntent == null) {
|
mMaster.clientRemoved(mUserId, callingPackage);
|
||||||
Slog.d(TAG, "No registration found for " + callingPackage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from existing requests
|
|
||||||
mExistingPendingIntents.remove(pendingIntent);
|
|
||||||
stopDetection(pendingIntent.getCreatorPackage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +256,7 @@ final class AmbientContextManagerPerUserService extends
|
|||||||
if (!setUpServiceIfNeeded()) {
|
if (!setUpServiceIfNeeded()) {
|
||||||
Slog.w(TAG, "Detection service is not available at this moment.");
|
Slog.w(TAG, "Detection service is not available at this moment.");
|
||||||
sendStatusToCallback(statusCallback,
|
sendStatusToCallback(statusCallback,
|
||||||
AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
|
AmbientContextManager.STATUS_NOT_SUPPORTED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ensureRemoteServiceInitiated();
|
ensureRemoteServiceInitiated();
|
||||||
@@ -382,16 +373,6 @@ final class AmbientContextManagerPerUserService extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private PendingIntent findExistingRequestByPackage(String callingPackage) {
|
|
||||||
for (PendingIntent pendingIntent : mExistingPendingIntents) {
|
|
||||||
if (pendingIntent.getCreatorPackage().equals(callingPackage)) {
|
|
||||||
return pendingIntent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends out the Intent to the client after the event is detected.
|
* Sends out the Intent to the client after the event is detected.
|
||||||
*
|
*
|
||||||
@@ -418,22 +399,22 @@ final class AmbientContextManagerPerUserService extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private RemoteCallback createDetectionResultRemoteCallback() {
|
RemoteCallback createDetectionResultRemoteCallback() {
|
||||||
return new RemoteCallback(result -> {
|
return new RemoteCallback(result -> {
|
||||||
AmbientContextDetectionResult detectionResult =
|
AmbientContextDetectionResult detectionResult =
|
||||||
(AmbientContextDetectionResult) result.get(
|
(AmbientContextDetectionResult) result.get(
|
||||||
AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
|
AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
|
||||||
|
String packageName = detectionResult.getPackageName();
|
||||||
|
PendingIntent pendingIntent = mMaster.getPendingIntent(mUserId, packageName);
|
||||||
|
if (pendingIntent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
for (PendingIntent pendingIntent : mExistingPendingIntents) {
|
|
||||||
// Send PendingIntent to requesting packages
|
|
||||||
String creatorPackage = pendingIntent.getCreatorPackage();
|
|
||||||
if (detectionResult.getPackageName().equals(creatorPackage)) {
|
|
||||||
sendDetectionResultIntent(pendingIntent, detectionResult);
|
sendDetectionResultIntent(pendingIntent, detectionResult);
|
||||||
Slog.i(TAG, "Got detection result of " + detectionResult.getEvents()
|
Slog.i(TAG, "Got detection result of " + detectionResult.getEvents()
|
||||||
+ " for " + creatorPackage);
|
+ " for " + packageName);
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static android.provider.DeviceConfig.NAMESPACE_AMBIENT_CONTEXT_MANAGER_SE
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.ambientcontext.AmbientContextEvent;
|
import android.app.ambientcontext.AmbientContextEvent;
|
||||||
@@ -34,6 +35,7 @@ import android.os.ResultReceiver;
|
|||||||
import android.os.ShellCallback;
|
import android.os.ShellCallback;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
@@ -60,9 +62,50 @@ public class AmbientContextManagerService extends
|
|||||||
|
|
||||||
/** Default value in absence of {@link DeviceConfig} override. */
|
/** Default value in absence of {@link DeviceConfig} override. */
|
||||||
private static final boolean DEFAULT_SERVICE_ENABLED = true;
|
private static final boolean DEFAULT_SERVICE_ENABLED = true;
|
||||||
|
public static final int MAX_TEMPORARY_SERVICE_DURATION_MS = 30000;
|
||||||
|
|
||||||
|
static class ClientRequest {
|
||||||
|
private final int mUserId;
|
||||||
|
private final AmbientContextEventRequest mRequest;
|
||||||
|
private final PendingIntent mPendingIntent;
|
||||||
|
private final RemoteCallback mClientStatusCallback;
|
||||||
|
|
||||||
|
ClientRequest(int userId, AmbientContextEventRequest request,
|
||||||
|
PendingIntent pendingIntent, RemoteCallback clientStatusCallback) {
|
||||||
|
this.mUserId = userId;
|
||||||
|
this.mRequest = request;
|
||||||
|
this.mPendingIntent = pendingIntent;
|
||||||
|
this.mClientStatusCallback = clientStatusCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getPackageName() {
|
||||||
|
return mPendingIntent.getCreatorPackage();
|
||||||
|
}
|
||||||
|
|
||||||
|
AmbientContextEventRequest getRequest() {
|
||||||
|
return mRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingIntent getPendingIntent() {
|
||||||
|
return mPendingIntent;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteCallback getClientStatusCallback() {
|
||||||
|
return mClientStatusCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasUserId(int userId) {
|
||||||
|
return mUserId == userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasUserIdAndPackageName(int userId, String packageName) {
|
||||||
|
return (userId == mUserId) && packageName.equals(getPackageName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
boolean mIsServiceEnabled;
|
boolean mIsServiceEnabled;
|
||||||
|
private Set<ClientRequest> mExistingClientRequests;
|
||||||
|
|
||||||
public AmbientContextManagerService(Context context) {
|
public AmbientContextManagerService(Context context) {
|
||||||
super(context,
|
super(context,
|
||||||
@@ -73,6 +116,7 @@ public class AmbientContextManagerService extends
|
|||||||
PACKAGE_UPDATE_POLICY_REFRESH_EAGER
|
PACKAGE_UPDATE_POLICY_REFRESH_EAGER
|
||||||
| /*To avoid high latency*/ PACKAGE_RESTART_POLICY_REFRESH_EAGER);
|
| /*To avoid high latency*/ PACKAGE_RESTART_POLICY_REFRESH_EAGER);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
mExistingClientRequests = new ArraySet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,6 +138,44 @@ public class AmbientContextManagerService extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void newClientAdded(int userId, AmbientContextEventRequest request,
|
||||||
|
PendingIntent pendingIntent, RemoteCallback clientStatusCallback) {
|
||||||
|
Slog.d(TAG, "New client added: " + pendingIntent.getCreatorPackage());
|
||||||
|
|
||||||
|
// Remove any existing ClientRequest for this user and package.
|
||||||
|
mExistingClientRequests.removeAll(
|
||||||
|
findExistingRequests(userId, pendingIntent.getCreatorPackage()));
|
||||||
|
|
||||||
|
// Add to existing ClientRequests
|
||||||
|
mExistingClientRequests.add(
|
||||||
|
new ClientRequest(userId, request, pendingIntent, clientStatusCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clientRemoved(int userId, String packageName) {
|
||||||
|
Slog.d(TAG, "Remove client: " + packageName);
|
||||||
|
mExistingClientRequests.removeAll(findExistingRequests(userId, packageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<ClientRequest> findExistingRequests(int userId, String packageName) {
|
||||||
|
Set<ClientRequest> existingRequests = new ArraySet<>();
|
||||||
|
for (ClientRequest clientRequest : mExistingClientRequests) {
|
||||||
|
if (clientRequest.hasUserIdAndPackageName(userId, packageName)) {
|
||||||
|
existingRequests.add(clientRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return existingRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
PendingIntent getPendingIntent(int userId, String packageName) {
|
||||||
|
for (ClientRequest clientRequest : mExistingClientRequests) {
|
||||||
|
if (clientRequest.hasUserIdAndPackageName(userId, packageName)) {
|
||||||
|
return clientRequest.getPendingIntent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void onDeviceConfigChange(@NonNull Set<String> keys) {
|
private void onDeviceConfigChange(@NonNull Set<String> keys) {
|
||||||
if (keys.contains(KEY_SERVICE_ENABLED)) {
|
if (keys.contains(KEY_SERVICE_ENABLED)) {
|
||||||
mIsServiceEnabled = DeviceConfig.getBoolean(
|
mIsServiceEnabled = DeviceConfig.getBoolean(
|
||||||
@@ -111,9 +193,33 @@ public class AmbientContextManagerService extends
|
|||||||
@Override
|
@Override
|
||||||
protected void onServiceRemoved(
|
protected void onServiceRemoved(
|
||||||
AmbientContextManagerPerUserService service, @UserIdInt int userId) {
|
AmbientContextManagerPerUserService service, @UserIdInt int userId) {
|
||||||
|
Slog.d(TAG, "onServiceRemoved");
|
||||||
service.destroyLocked();
|
service.destroyLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
|
||||||
|
Slog.d(TAG, "Restoring remote request. Reason: Service package restarted.");
|
||||||
|
restorePreviouslyEnabledClients(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
|
||||||
|
Slog.d(TAG, "Restoring remote request. Reason: Service package updated.");
|
||||||
|
restorePreviouslyEnabledClients(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void enforceCallingPermissionForManagement() {
|
||||||
|
getContext().enforceCallingPermission(
|
||||||
|
Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getMaximumTemporaryServiceDurationMs() {
|
||||||
|
return MAX_TEMPORARY_SERVICE_DURATION_MS;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns {@code true} if the detection service is configured on this device. */
|
/** Returns {@code true} if the detection service is configured on this device. */
|
||||||
public static boolean isDetectionServiceConfigured() {
|
public static boolean isDetectionServiceConfigured() {
|
||||||
final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
|
final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
|
||||||
@@ -182,6 +288,22 @@ public class AmbientContextManagerService extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void restorePreviouslyEnabledClients(int userId) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
final AmbientContextManagerPerUserService service = getServiceForUserLocked(userId);
|
||||||
|
for (ClientRequest clientRequest : mExistingClientRequests) {
|
||||||
|
// Start detection for previously enabled clients
|
||||||
|
if (clientRequest.hasUserId(userId)) {
|
||||||
|
Slog.d(TAG, "Restoring detection for " + clientRequest.getPackageName());
|
||||||
|
service.startDetection(clientRequest.getRequest(),
|
||||||
|
clientRequest.getPackageName(),
|
||||||
|
service.createDetectionResultRemoteCallback(),
|
||||||
|
clientRequest.getClientStatusCallback());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the AmbientContextManagerPerUserService component for this user.
|
* Returns the AmbientContextManagerPerUserService component for this user.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user