Merge "Stabalize AmbientContext detection by restoring client requests." into tm-dev
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user