Merge "Stabalize AmbientContext detection by restoring client requests." into tm-dev

This commit is contained in:
Kathy Chen
2022-04-25 20:49:28 +00:00
committed by Android (Google) Code Review
2 changed files with 156 additions and 53 deletions

View File

@@ -43,7 +43,6 @@ import android.os.RemoteException;
import android.service.ambientcontext.AmbientContextDetectionResult;
import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -54,7 +53,6 @@ import com.android.server.infra.AbstractPerUserSystemService;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
/**
* Per-user manager service for {@link AmbientContextEvent}s.
@@ -69,19 +67,13 @@ final class AmbientContextManagerPerUserService extends
RemoteAmbientContextDetectionService mRemoteService;
private ComponentName mComponentName;
private Set<PendingIntent> mExistingPendingIntents;
AmbientContextManagerPerUserService(
@NonNull AmbientContextManagerService master, Object lock, @UserIdInt int userId) {
super(master, lock, userId);
mExistingPendingIntents = new ArraySet<>();
}
void destroyLocked() {
if (isVerbose()) {
Slog.v(TAG, "destroyLocked()");
}
Slog.d(TAG, "Trying to cancel the remote request. Reason: Service destroyed.");
if (mRemoteService != null) {
synchronized (mLock) {
@@ -118,7 +110,19 @@ final class AmbientContextManagerPerUserService extends
if (mComponentName == null) {
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
@@ -171,18 +175,10 @@ final class AmbientContextManagerPerUserService extends
return;
}
// Remove any existing PendingIntent for this package.
String callingPackage = pendingIntent.getCreatorPackage();
PendingIntent duplicatePendingIntent = findExistingRequestByPackage(callingPackage);
if (duplicatePendingIntent != null) {
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);
// Register package and add to existing ClientRequests cache
startDetection(request, pendingIntent.getCreatorPackage(),
createDetectionResultRemoteCallback(), clientStatusCallback);
mMaster.newClientAdded(mUserId, request, pendingIntent, clientStatusCallback);
}
}
@@ -214,15 +210,17 @@ final class AmbientContextManagerPerUserService extends
@VisibleForTesting
void startDetection(AmbientContextEventRequest request, String callingPackage,
RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
RemoteCallback detectionResultCallback, RemoteCallback clientStatusCallback) {
Slog.d(TAG, "Requested detection of " + request.getEventTypes());
synchronized (mLock) {
if (setUpServiceIfNeeded()) {
ensureRemoteServiceInitiated();
mRemoteService.startDetection(request, callingPackage, detectionResultCallback,
statusCallback);
getServerStatusCallback(clientStatusCallback));
} else {
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) {
synchronized (mLock) {
PendingIntent pendingIntent = findExistingRequestByPackage(callingPackage);
if (pendingIntent == null) {
Slog.d(TAG, "No registration found for " + callingPackage);
return;
}
// Remove from existing requests
mExistingPendingIntents.remove(pendingIntent);
stopDetection(pendingIntent.getCreatorPackage());
stopDetection(callingPackage);
mMaster.clientRemoved(mUserId, callingPackage);
}
}
@@ -265,7 +256,7 @@ final class AmbientContextManagerPerUserService extends
if (!setUpServiceIfNeeded()) {
Slog.w(TAG, "Detection service is not available at this moment.");
sendStatusToCallback(statusCallback,
AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
AmbientContextManager.STATUS_NOT_SUPPORTED);
return;
}
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.
*
@@ -418,22 +399,22 @@ final class AmbientContextManagerPerUserService extends
}
@NonNull
private RemoteCallback createDetectionResultRemoteCallback() {
RemoteCallback createDetectionResultRemoteCallback() {
return new RemoteCallback(result -> {
AmbientContextDetectionResult detectionResult =
(AmbientContextDetectionResult) result.get(
AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
String packageName = detectionResult.getPackageName();
PendingIntent pendingIntent = mMaster.getPendingIntent(mUserId, packageName);
if (pendingIntent == null) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
for (PendingIntent pendingIntent : mExistingPendingIntents) {
// Send PendingIntent to requesting packages
String creatorPackage = pendingIntent.getCreatorPackage();
if (detectionResult.getPackageName().equals(creatorPackage)) {
sendDetectionResultIntent(pendingIntent, detectionResult);
Slog.i(TAG, "Got detection result of " + detectionResult.getEvents()
+ " for " + creatorPackage);
}
}
sendDetectionResultIntent(pendingIntent, detectionResult);
Slog.i(TAG, "Got detection result of " + detectionResult.getEvents()
+ " for " + packageName);
} finally {
Binder.restoreCallingIdentity(token);
}

View File

@@ -20,6 +20,7 @@ import static android.provider.DeviceConfig.NAMESPACE_AMBIENT_CONTEXT_MANAGER_SE
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.app.ambientcontext.AmbientContextEvent;
@@ -34,6 +35,7 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.R;
@@ -60,9 +62,50 @@ public class AmbientContextManagerService extends
/** Default value in absence of {@link DeviceConfig} override. */
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;
boolean mIsServiceEnabled;
private Set<ClientRequest> mExistingClientRequests;
public AmbientContextManagerService(Context context) {
super(context,
@@ -73,6 +116,7 @@ public class AmbientContextManagerService extends
PACKAGE_UPDATE_POLICY_REFRESH_EAGER
| /*To avoid high latency*/ PACKAGE_RESTART_POLICY_REFRESH_EAGER);
mContext = context;
mExistingClientRequests = new ArraySet<>();
}
@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) {
if (keys.contains(KEY_SERVICE_ENABLED)) {
mIsServiceEnabled = DeviceConfig.getBoolean(
@@ -111,9 +193,33 @@ public class AmbientContextManagerService extends
@Override
protected void onServiceRemoved(
AmbientContextManagerPerUserService service, @UserIdInt int userId) {
Slog.d(TAG, "onServiceRemoved");
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. */
public static boolean isDetectionServiceConfigured() {
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.
*/