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

Commit 44b586e0 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Initial implementation of ContentCaptureService.setContentCaptureWhitelist()"

parents db7bdd46 e8eae9d4
Loading
Loading
Loading
Loading
+17 −11
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.service.autofill.AutofillService;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.view.contentcapture.ContentCaptureContext;
@@ -171,16 +172,11 @@ public abstract class ContentCaptureService extends Service {
    @Deprecated
    public final void setContentCaptureWhitelist(@Nullable List<String> packages,
            @Nullable List<ComponentName> activities) {
        final IContentCaptureServiceCallback callback = mCallback;
        if (callback == null) {
            Log.w(TAG, "setContentCaptureWhitelist(): no server callback");
            return;
        }
        try {
            callback.setContentCaptureWhitelist(packages, activities);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        setContentCaptureWhitelist(toSet(packages), toSet(activities));
    }

    private <T> ArraySet<T> toSet(@Nullable List<T> set) {
        return set == null ? null : new ArraySet<T>(set);
    }

    /**
@@ -197,7 +193,17 @@ public abstract class ContentCaptureService extends Service {
     */
    public final void setContentCaptureWhitelist(@Nullable Set<String> packages,
            @Nullable Set<ComponentName> activities) {
        setContentCaptureWhitelist(toList(packages), toList(activities));
        final IContentCaptureServiceCallback callback = mCallback;
        if (callback == null) {
            Log.w(TAG, "setContentCaptureWhitelist(): no server callback");
            return;
        }

        try {
            callback.setContentCaptureWhitelist(toList(packages), toList(activities));
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
    }

    private <T> ArrayList<T> toList(@Nullable Set<T> set) {
+7 −0
Original line number Diff line number Diff line
@@ -120,6 +120,13 @@ public abstract class ContentCaptureSession implements AutoCloseable {
     */
    public static final int STATE_INTERNAL_ERROR = 0x100;

    /**
     * Session is disabled because service didn't whitelist package.
     *
     * @hide
     */
    public static final int STATE_PACKAGE_NOT_WHITELISTED = 0x200;

    private static final int INITIAL_CHILDREN_CAPACITY = 5;

    /** @hide */
+57 −8
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
import static android.view.contentcapture.ContentCaptureSession.STATE_INTERNAL_ERROR;
import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE;
import static android.view.contentcapture.ContentCaptureSession.STATE_PACKAGE_NOT_WHITELISTED;

import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
@@ -47,7 +48,7 @@ import android.service.contentcapture.ContentCaptureService;
import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
import android.util.ArrayMap;
import android.util.Log;
import android.util.ArraySet;
import android.util.Slog;
import android.view.contentcapture.UserDataRemovalRequest;

@@ -87,6 +88,12 @@ final class ContentCapturePerUserService
    private final ContentCaptureServiceRemoteCallback mRemoteServiceCallback =
            new ContentCaptureServiceRemoteCallback();

    /**
     * List of packages that are whitelisted to be content captured.
     */
    @GuardedBy("mLock")
    private final ArraySet<String> mWhitelistedPackages = new ArraySet<>();

    // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's

    ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
@@ -185,6 +192,7 @@ final class ContentCapturePerUserService
        final int taskId = activityPresentationInfo.taskId;
        final int displayId = activityPresentationInfo.displayId;
        final ComponentName componentName = activityPresentationInfo.componentName;
        final boolean whitelisted = isWhitelistedLocked(componentName);
        final ComponentName serviceComponentName = getServiceComponentName();
        final boolean enabled = isEnabledLocked();
        if (mMaster.mRequestsHistory != null) {
@@ -193,7 +201,8 @@ final class ContentCapturePerUserService
                    + " a=" + ComponentName.flattenToShortString(componentName)
                    + " t=" + taskId + " d=" + displayId
                    + " s=" + ComponentName.flattenToShortString(serviceComponentName)
                    + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)");
                    + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)")
                    + " w=" + whitelisted;
            mMaster.mRequestsHistory.log(historyItem);
        }

@@ -214,6 +223,16 @@ final class ContentCapturePerUserService
            return;
        }

        if (!whitelisted) {
            if (mMaster.debug) {
                Slog.d(TAG, "startSession(" + componentName + "): not whitelisted");
            }
            // TODO(b/122595322): need to return STATE_ACTIVITY_NOT_WHITELISTED as well
            setClientState(clientReceiver, STATE_DISABLED | STATE_PACKAGE_NOT_WHITELISTED,
                    /* binder= */ null);
            return;
        }

        final ContentCaptureServerSession existingSession = mSessions.get(sessionId);
        if (existingSession != null) {
            Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
@@ -247,6 +266,26 @@ final class ContentCapturePerUserService
        newSession.notifySessionStartedLocked(clientReceiver);
    }

    @GuardedBy("mLock")
    private boolean isWhitelistedLocked(@NonNull ComponentName componentName) {
        // TODO(b/122595322): need to check whitelisted activities as well.
        final String packageName = componentName.getPackageName();
        return mWhitelistedPackages.contains(packageName);
    }

    private void whitelistPackages(@NonNull List<String> packages) {
        // TODO(b/122595322): add CTS test for when it's null
        synchronized (mLock) {
            if (packages == null) {
                if (mMaster.verbose) Slog.v(TAG, "clearing all whitelisted packages");
                mWhitelistedPackages.clear();
            } else {
                if (mMaster.verbose) Slog.v(TAG, "whitelisting packages: " + packages);
                mWhitelistedPackages.addAll(packages);
            }
        }
    }

    // TODO(b/119613670): log metrics
    @GuardedBy("mLock")
    public void finishSessionLocked(@NonNull String sessionId) {
@@ -378,15 +417,23 @@ final class ContentCapturePerUserService
            mRemoteService.dump(prefix2, pw);
        }

        final int whitelistSize = mWhitelistedPackages.size();
        pw.print(prefix); pw.print("Whitelisted packages: "); pw.println(whitelistSize);
        for (int i = 0; i < whitelistSize; i++) {
            final String whitelistedPkg = mWhitelistedPackages.valueAt(i);
            pw.print(prefix2); pw.print(i + 1); pw.print(": "); pw.println(whitelistedPkg);
        }

        if (mSessions.isEmpty()) {
            pw.print(prefix); pw.println("no sessions");
        } else {
            final int size = mSessions.size();
            pw.print(prefix); pw.print("number sessions: "); pw.println(size);
            for (int i = 0; i < size; i++) {
                pw.print(prefix); pw.print("session@"); pw.println(i);
            final int sessionsSize = mSessions.size();
            pw.print(prefix); pw.print("number sessions: "); pw.println(sessionsSize);
            for (int i = 0; i < sessionsSize; i++) {
                pw.print(prefix); pw.print("#"); pw.println(i);
                final ContentCaptureServerSession session = mSessions.valueAt(i);
                session.dumpLocked(prefix2, pw);
                pw.println();
            }
        }
    }
@@ -412,10 +459,12 @@ final class ContentCapturePerUserService
        public void setContentCaptureWhitelist(List<String> packages,
                List<ComponentName> activities) {
            if (mMaster.verbose) {
                Log.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
                Slog.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
                        + activities + ")");
            }
            // TODO(b/122595322): implement
            whitelistPackages(packages);

            // TODO(b/122595322): whitelist activities as well
            // TODO(b/119613670): log metrics
        }
    }