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

Commit 393c96de authored by Connie Huang's avatar Connie Huang
Browse files

Invalidate the CSS token after default duration (10 minutes) to improve security.

See go/l2a-css. This change also adds an adb command to set the token
validity duration for testing purposes. The duration cannot exceed the
default token duration.
`adb shell cmd contextual_search set token-duration 200000`

Bug: 338598282
Test: CTS and manual tests
Change-Id: I0f996f5f6f3eaaf12900dbebd44d9c8d04308f15
(cherry picked from commit 7de3d5d3cdc7c516edcf0062c9a3ca4acee9bce1)

Modify ContextualSearchService to refresh token in the callback.

Checks the enableTokenRefresh aconfig flag to determine if CSS should
call the callback with a new token each time getContextualSearchState
is called. If true, the callback will be called twice:
- Once with a fresh token for the next getContextualSearchState call.
- A second time with the assist state.

FLAG:android.app.contextualsearch.flags.enable_token_refreshBug: 338598282
Test: CTS and tested on device
Change-Id: I73c2db2758b396482d1f4e78d50febf0606eb8ad
parent 6cdb4905
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -7,3 +7,9 @@ flag {
  description: "Flag to enable the service"
  bug: "309689654"
}
flag {
  name: "enable_token_refresh"
  namespace: "machine_learning"
  description: "Flag to refresh the token to the callback"
  bug: "309689654"
}
 No newline at end of file
+77 −2
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.app.contextualsearch.ContextualSearchManager;
import android.app.contextualsearch.ContextualSearchState;
import android.app.contextualsearch.IContextualSearchCallback;
import android.app.contextualsearch.IContextualSearchManager;
import android.app.contextualsearch.flags.Flags;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -91,6 +92,8 @@ public class ContextualSearchManagerService extends SystemService {
    private static final String TAG = ContextualSearchManagerService.class.getSimpleName();
    private static final int MSG_RESET_TEMPORARY_PACKAGE = 0;
    private static final int MAX_TEMP_PACKAGE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
    private static final int MSG_INVALIDATE_TOKEN = 1;
    private static final int MAX_TOKEN_VALID_DURATION_MS = 1_000 * 60 * 10; // 10 minutes

    private final Context mContext;
    private final ActivityTaskManagerInternal mAtmInternal;
@@ -145,6 +148,8 @@ public class ContextualSearchManagerService extends SystemService {
    private Handler mTemporaryHandler;
    @GuardedBy("this")
    private String mTemporaryPackage = null;
    @GuardedBy("this")
    private long mTokenValidDurationMs = MAX_TOKEN_VALID_DURATION_MS;

    @GuardedBy("mLock")
    private IContextualSearchCallback mStateCallback;
@@ -212,6 +217,29 @@ public class ContextualSearchManagerService extends SystemService {
        }
    }

    void resetTokenValidDurationMs() {
        setTokenValidDurationMs(MAX_TOKEN_VALID_DURATION_MS);
    }

    void setTokenValidDurationMs(int durationMs) {
        synchronized (this) {
            enforceOverridingPermission("setTokenValidDurationMs");
            if (durationMs > MAX_TOKEN_VALID_DURATION_MS) {
                throw new IllegalArgumentException(
                        "Token max duration is " + MAX_TOKEN_VALID_DURATION_MS + " (called with "
                                + durationMs + ")");
            }
            mTokenValidDurationMs = durationMs;
            if (DEBUG_USER) Log.d(TAG, "mTokenValidDurationMs set to " + durationMs);
        }
    }

    private long getTokenValidDurationMs() {
        synchronized (this) {
            return mTokenValidDurationMs;
        }
    }

    private Intent getResolvedLaunchIntent() {
        synchronized (this) {
            // If mTemporaryPackage is not null, use it to get the ContextualSearch intent.
@@ -356,15 +384,51 @@ public class ContextualSearchManagerService extends SystemService {
    }

    private class ContextualSearchManagerStub extends IContextualSearchManager.Stub {
        @GuardedBy("this")
        private Handler mTokenHandler;
        private @Nullable CallbackToken mToken;

        private void invalidateToken() {
            synchronized (this) {
                if (mTokenHandler != null) {
                    mTokenHandler.removeMessages(MSG_INVALIDATE_TOKEN);
                    mTokenHandler = null;
                }
                if (DEBUG_USER) Log.d(TAG, "mToken invalidated.");
                mToken = null;
            }
        }

        private void issueToken() {
            synchronized (this) {
                mToken = new CallbackToken();
                if (mTokenHandler == null) {
                    mTokenHandler = new Handler(Looper.getMainLooper(), null, true) {
                        @Override
                        public void handleMessage(Message msg) {
                            if (msg.what == MSG_INVALIDATE_TOKEN) {
                                invalidateToken();
                            } else {
                                Slog.wtf(TAG, "invalid token handler msg: " + msg);
                            }
                        }
                    };
                } else {
                    mTokenHandler.removeMessages(MSG_INVALIDATE_TOKEN);
                }
                mTokenHandler.sendEmptyMessageDelayed(
                        MSG_INVALIDATE_TOKEN, getTokenValidDurationMs());
            }
        }

        @Override
        public void startContextualSearch(int entrypoint) {
            synchronized (this) {
                if (DEBUG_USER) Log.d(TAG, "startContextualSearch");
                enforcePermission("startContextualSearch");
                mAssistDataRequester.cancel();
                mToken = new CallbackToken();
                // Creates a new CallbackToken at mToken and an expiration handler.
                issueToken();
                // We get the launch intent with the system server's identity because the system
                // server has READ_FRAME_BUFFER permission to get the screenshot and because only
                // the system server can invoke non-exported activities.
@@ -397,7 +461,18 @@ public class ContextualSearchManagerService extends SystemService {
                }
                return;
            }
            mToken = null;
            invalidateToken();
            if (Flags.enableTokenRefresh()) {
                issueToken();
                Bundle bundle = new Bundle();
                bundle.putParcelable(ContextualSearchManager.EXTRA_TOKEN, mToken);
                try {
                    callback.onResult(
                            new ContextualSearchState(null, null, bundle));
                } catch (RemoteException e) {
                    Log.e(TAG, "Error invoking ContextualSearchCallback", e);
                }
            }
            synchronized (mLock) {
                mStateCallback = callback;
            }
+16 −0
Original line number Diff line number Diff line
@@ -52,6 +52,19 @@ public class ContextualSearchManagerShellCommand extends ShellCommand {
                                + packageName + " for " + duration + "ms");
                        break;
                    }
                    case "token-duration": {
                        String durationStr = getNextArg();
                        if (durationStr == null) {
                            mService.resetTokenValidDurationMs();
                            pw.println("ContextualSearchManagerService token duration reset.");
                            return 0;
                        }
                        final int durationMs = Integer.parseInt(durationStr);
                        mService.setTokenValidDurationMs(durationMs);
                        pw.println("ContextualSearchManagerService temporarily set token duration"
                                + " to " + durationMs + "ms");
                        break;
                    }
                }
            }
            break;
@@ -72,6 +85,9 @@ public class ContextualSearchManagerShellCommand extends ShellCommand {
            pw.println("    Temporarily (for DURATION ms) changes the Contextual Search "
                    + "implementation.");
            pw.println("    To reset, call without any arguments.");
            pw.println("  set token-duration [DURATION]");
            pw.println("    Changes the Contextual Search token duration to DURATION ms.");
            pw.println("    To reset, call without any arguments.");
            pw.println("");
        }
    }