Skip to content

Commit

Permalink
support for allowing one-time clipboard access to apps
Browse files Browse the repository at this point in the history
  • Loading branch information
octocorvus committed May 11, 2024
1 parent 31ffeb5 commit 90a76b1
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 2 deletions.
1 change: 1 addition & 0 deletions core/res/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6393,6 +6393,7 @@ ul.</string>
<string name="other_users_notification_switch_user_action">Switch to <xliff:g id="username" example="Bob">%1$s</xliff:g></string>

<string name="notification_action_dont_show_again">Don’t show again</string>
<string name="notification_action_allow_this_time">Allow this time</string>

<string name="notification_channel_missing_permission">Missing permission</string>
<string name="missing_sensors_permission_title">%1$s tried to access sensors</string>
Expand Down
1 change: 1 addition & 0 deletions core/res/res/values/symbols.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5315,6 +5315,7 @@
<java-symbol type="bool" name="config_quickSettingsShowMediaPlayer" />

<java-symbol type="string" name="notification_action_dont_show_again" />
<java-symbol type="string" name="notification_action_allow_this_time" />

<java-symbol type="string" name="notification_channel_missing_permission" />
<java-symbol type="string" name="missing_sensors_permission_title" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package android.content.clipboard;

/**
* @hide
*/
public abstract class ClipboardManagerInternal {
public abstract void setAllowOneTimeAccess(String pkg, int userId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.android.server.clipboard;

import static android.content.Context.DEVICE_ID_DEFAULT;

import android.content.clipboard.ClipboardManagerInternal;
import android.content.ClipData;
import android.content.Context;
import android.content.pm.ApplicationInfo;
Expand All @@ -8,15 +11,22 @@
import android.ext.SettingsIntents;
import android.ext.settings.app.AswDenyClipboardRead;
import android.os.Process;
import android.os.UserHandle;

import com.android.internal.R;
import com.android.server.LocalServices;
import com.android.server.ext.AppSwitchNotification;
import com.android.server.ext.IntentReceiver;
import com.android.server.pm.pkg.GosPackageStatePm;

class ClipboardHelper {
static final ClipData dummyClip = ClipData.newPlainText(null, "");

static int getPackageUid(String pkgName, int userId) {
var pmi = LocalServices.getService(PackageManagerInternal.class);
return pmi.getPackageUid(pkgName, 0, userId);
}

static boolean isReadBlockedForPackage(Context ctx, String pkgName, int userId) {
var pmi = LocalServices.getService(PackageManagerInternal.class);
ApplicationInfo appInfo = pmi.getApplicationInfo(pkgName, 0, Process.SYSTEM_UID, userId);
Expand All @@ -27,7 +37,7 @@ static boolean isReadBlockedForPackage(Context ctx, String pkgName, int userId)
return AswDenyClipboardRead.I.get(ctx, userId, appInfo, ps);
}

static void maybeNotifyAccessDenied(Context ctx, String pkgName, int userId) {
static void maybeNotifyAccessDenied(Context ctx, String pkgName, int userId, int deviceId) {
var pmi = LocalServices.getService(PackageManagerInternal.class);
ApplicationInfo appInfo = pmi.getApplicationInfo(pkgName, 0, Process.SYSTEM_UID, userId);
if (appInfo == null) {
Expand All @@ -36,6 +46,20 @@ static void maybeNotifyAccessDenied(Context ctx, String pkgName, int userId) {
var n = AppSwitchNotification.create(ctx, appInfo, SettingsIntents.APP_CLIPBOARD);
n.titleRes = R.string.notif_clipboard_read_deny_title;
n.gosPsFlagSuppressNotif = GosPackageState.FLAG_DENY_CLIPBOARD_READ_SUPPRESS_NOTIF;
// only show notification action to allow one-time access for default device
if (deviceId == DEVICE_ID_DEFAULT) {
IntentReceiver receiver = IntentReceiver.getInstance(
NotifActionReceiver.class, NotifActionReceiver::new, ctx);
n.setCustomNotifAction(receiver, R.string.notification_action_allow_this_time);
}
n.maybeShow();
}

static class NotifActionReceiver extends AppSwitchNotification.CustomNotifActionReceiver {
@Override
public void onReceive(Context ctx, String packageName, UserHandle user) {
var cmi = LocalServices.getService(ClipboardManagerInternal.class);
cmi.setAllowOneTimeAccess(packageName, user.getIdentifier());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import android.content.IOnPrimaryClipChangedListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.clipboard.ClipboardManagerInternal;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
Expand Down Expand Up @@ -212,6 +213,8 @@ public ClipboardService(Context context) {
HandlerThread workerThread = new HandlerThread(TAG);
workerThread.start();
mWorkerHandler = workerThread.getThreadHandler();

LocalServices.addService(ClipboardManagerInternal.class, new ClipboardManagerInternalImpl());
}

@Override
Expand Down Expand Up @@ -322,6 +325,9 @@ private static class Clipboard {
*/
final SparseBooleanArray mNotifiedTextClassifierUids = new SparseBooleanArray();

/** Uids that have access to current clip. */
final SparseBooleanArray mCurrentClipAllowedUids = new SparseBooleanArray();

final HashSet<String> activePermissionOwners
= new HashSet<String>();

Expand Down Expand Up @@ -888,6 +894,23 @@ public void handleMessage(@NonNull Message msg) {
}
};

private class ClipboardManagerInternalImpl extends ClipboardManagerInternal {
@Override
public void setAllowOneTimeAccess(String pkg, int userId) {
synchronized (mLock) {
int pkgUid = ClipboardHelper.getPackageUid(pkg, userId);
if (pkgUid < 0) {
return;
}
Clipboard clipboard = getClipboardLocked(userId, DEVICE_ID_DEFAULT);
if (clipboard == null) {
return;
}
clipboard.mCurrentClipAllowedUids.put(pkgUid, true);
}
}
}

@GuardedBy("mLock")
private @Nullable Clipboard getClipboardLocked(@UserIdInt int userId, int deviceId) {
Clipboard clipboard = mClipboards.get(userId, deviceId);
Expand Down Expand Up @@ -1034,6 +1057,7 @@ private void setPrimaryClipInternalNoClassifyLocked(Clipboard clipboard,
clipboard.primaryClip = clip;
clipboard.mNotifiedUids.clear();
clipboard.mNotifiedTextClassifierUids.clear();
clipboard.mCurrentClipAllowedUids.clear();
if (clip != null) {
clipboard.primaryClipUid = uid;
clipboard.mPrimaryClipPackage = sourcePackage;
Expand Down Expand Up @@ -1498,7 +1522,7 @@ private void showAccessNotificationLocked(String callingPackage, int uid, @UserI
Slog.d(TAG, "clipboard read blocked for: " + callingPackage);
Binder.withCleanCallingIdentity(
() -> ClipboardHelper.maybeNotifyAccessDenied(
getContext(), callingPackage, userId));
getContext(), callingPackage, userId, clipboard.deviceId));
return;
}

Expand Down Expand Up @@ -1648,6 +1672,7 @@ private TextClassificationManager createTextClassificationManagerAsUser(@UserIdI

private boolean isReadBlockedForPkg(int uid, String pkg, int userId, Clipboard clipboard) {
return uid != clipboard.primaryClipUid
&& !clipboard.mCurrentClipAllowedUids.get(uid)
&& ClipboardHelper.isReadBlockedForPackage(getContext(), pkg, userId);
}
}

0 comments on commit 90a76b1

Please sign in to comment.