Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 889d4894 authored by Kathy Chen's avatar Kathy Chen Committed by Android (Google) Code Review
Browse files

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

parents a9fad69c 57999bac
Loading
Loading
Loading
Loading
+34 −53
Original line number Diff line number Diff line
@@ -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);
                    }
                }
                        + " for " + packageName);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
+122 −0
Original line number Diff line number Diff line
@@ -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.
     */