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

Commit addabbaf authored by Perumaal S's avatar Perumaal S
Browse files

Implement getServiceComponentName API for Content Capture

Tests are in ag/5989968

Fixes: 121047489
Test: atest CtsContentCaptureServiceTestCases # to make sure nothing broke
Test: atest
CtsContentCaptureServiceTestCases:android.contentcaptureservice.cts.BlankActivityTest#testTargetServiceName_enabled
Test: google3 test with test app
Change-Id: I4f11a324beb938a28cd150c35bb3d83c77e59e0b
parent 959d407a
Loading
Loading
Loading
Loading
+35 −2
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
package android.view.contentcapture;

import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
@@ -24,9 +26,12 @@ import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.android.internal.os.IResultReceiver;
import com.android.internal.util.Preconditions;
import com.android.internal.util.SyncResultReceiver;

import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -48,6 +53,11 @@ public final class ContentCaptureManager {

    private static final String BG_THREAD_NAME = "intel_svc_streamer_thread";

    /**
     * Timeout for calls to system_server.
     */
    private static final int SYNC_CALLS_TIMEOUT_MS = 5000;

    // TODO(b/121044306): define a way to dynamically set them(for example, using settings?)
    static final boolean VERBOSE = false;
    static final boolean DEBUG = true; // STOPSHIP if not set to false
@@ -142,9 +152,22 @@ public final class ContentCaptureManager {
     */
    @Nullable
    public ComponentName getServiceComponentName() {
        //TODO(b/121047489): implement
        if (!isContentCaptureEnabled()) {
            return null;
        }
        // Wait for system server to return the component name.
        final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
        mHandler.sendMessage(obtainMessage(
                ContentCaptureManager::handleReceiverServiceComponentName,
                this, mContext.getUserId(), resultReceiver));

        try {
            return resultReceiver.getParcelableResult();
        } catch (RemoteException e) {
            // Unable to retrieve component name in a reasonable amount of time.
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Checks whether content capture is enabled for this activity.
@@ -191,4 +214,14 @@ public final class ContentCaptureManager {
            pw.print(prefix); pw.println("No sessions");
        }
    }


    /** Retrieves the component name of the target content capture service through system_server. */
    private void handleReceiverServiceComponentName(int userId, IResultReceiver resultReceiver) {
        try {
            mService.getReceiverServiceComponentName(userId, resultReceiver);
        } catch (RemoteException e) {
            Log.w(TAG, "Unable to retrieve service component name: " + e);
        }
    }
}
+21 −0
Original line number Diff line number Diff line
@@ -32,7 +32,28 @@ import java.util.List;
  * @hide
  */
oneway interface IContentCaptureManager {
    /**
     * Starts a new session for the provided {@code userId} running as part of the
     * app's activity identified by {@code activityToken}/{@code componentName}.
     *
     * @param sessionId Unique session id as provided by the app.
     * @param flags Meta flags that enable or disable content capture (see
     *     {@link IContentCaptureContext#flags}).
     */
    void startSession(int userId, IBinder activityToken, in ComponentName componentName,
                      String sessionId, int flags, in IResultReceiver result);

    /**
     * Marks the end of a session for the provided {@code userId} identified by
     * the corresponding {@code startSession}'s {@code sessionId}.
     */
    void finishSession(int userId, String sessionId);

    /**
     * Returns the content capture service's component name (if enabled and
     * connected).
     * @param Receiver of the content capture service's @{code ComponentName}
     *     provided {@code Bundle} with key "{@code EXTRA}".
     */
    void getReceiverServiceComponentName(int userId, in IResultReceiver result);
}
+20 −2
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.SyncResultReceiver;
import com.android.server.LocalServices;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -50,8 +51,9 @@ import java.util.ArrayList;
/**
 * A service used to observe the contents of the screen.
 *
 * <p>The data collected by this service can be analyzed and combined with other sources to provide
 * contextual data in other areas of the system such as Autofill.
 * <p>The data collected by this service can be analyzed on-device and combined
 * with other sources to provide contextual data in other areas of the system
 * such as Autofill.
 */
public final class ContentCaptureManagerService extends
        AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> {
@@ -195,6 +197,22 @@ public final class ContentCaptureManagerService extends
            }
        }

        @Override
        public void getReceiverServiceComponentName(@UserIdInt int userId,
                IResultReceiver receiver) {
            ComponentName connectedServiceComponentName;
            synchronized (mLock) {
                final ContentCapturePerUserService service = getServiceForUserLocked(userId);
                connectedServiceComponentName = service.getServiceComponentName();
            }
            try {
                receiver.send(0, SyncResultReceiver.bundleFor(connectedServiceComponentName));
            } catch (RemoteException e) {
                // Ignore exception as we need to be resilient against app behavior.
                Slog.w(TAG, "Unable to send service component name: " + e);
            }
        }

        @Override
        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;