Merge "Propagate ContentCaptureManager allowlist update to activities" into sc-dev am: d77366e4f2
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13634645 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: Icb217df0361b3751df45d11c0fc13ed347a8e3dc
This commit is contained in:
@@ -176,6 +176,8 @@ import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.view.autofill.AutofillId;
|
||||
import android.view.contentcapture.IContentCaptureManager;
|
||||
import android.view.contentcapture.IContentCaptureOptionsCallback;
|
||||
import android.view.translation.TranslationSpec;
|
||||
import android.webkit.WebView;
|
||||
import android.window.SplashScreen;
|
||||
@@ -512,6 +514,8 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
|
||||
boolean mHasImeComponent = false;
|
||||
|
||||
private IContentCaptureOptionsCallback.Stub mContentCaptureOptionsCallback = null;
|
||||
|
||||
/** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
|
||||
public static final class ActivityClientRecord {
|
||||
@UnsupportedAppUsage
|
||||
@@ -1939,6 +1943,7 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
public static final int PURGE_RESOURCES = 161;
|
||||
public static final int ATTACH_STARTUP_AGENTS = 162;
|
||||
public static final int UPDATE_UI_TRANSLATION_STATE = 163;
|
||||
public static final int SET_CONTENT_CAPTURE_OPTIONS_CALLBACK = 164;
|
||||
|
||||
public static final int INSTRUMENT_WITHOUT_RESTART = 170;
|
||||
public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171;
|
||||
@@ -1988,6 +1993,8 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
case PURGE_RESOURCES: return "PURGE_RESOURCES";
|
||||
case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
|
||||
case UPDATE_UI_TRANSLATION_STATE: return "UPDATE_UI_TRANSLATION_STATE";
|
||||
case SET_CONTENT_CAPTURE_OPTIONS_CALLBACK:
|
||||
return "SET_CONTENT_CAPTURE_OPTIONS_CALLBACK";
|
||||
case INSTRUMENT_WITHOUT_RESTART: return "INSTRUMENT_WITHOUT_RESTART";
|
||||
case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
|
||||
return "FINISH_INSTRUMENTATION_WITHOUT_RESTART";
|
||||
@@ -2180,6 +2187,9 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
(TranslationSpec) args.arg3, (TranslationSpec) args.arg4,
|
||||
(List<AutofillId>) args.arg5);
|
||||
break;
|
||||
case SET_CONTENT_CAPTURE_OPTIONS_CALLBACK:
|
||||
handleSetContentCaptureOptionsCallback((String) msg.obj);
|
||||
break;
|
||||
case INSTRUMENT_WITHOUT_RESTART:
|
||||
handleInstrumentWithoutRestart((AppBindData) msg.obj);
|
||||
break;
|
||||
@@ -6795,6 +6805,7 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
|
||||
// Propagate Content Capture options
|
||||
app.setContentCaptureOptions(data.contentCaptureOptions);
|
||||
sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName);
|
||||
|
||||
mInitialApplication = app;
|
||||
|
||||
@@ -6856,6 +6867,36 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSetContentCaptureOptionsCallback(String packageName) {
|
||||
if (mContentCaptureOptionsCallback != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IBinder b = ServiceManager.getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
|
||||
if (b == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(b);
|
||||
mContentCaptureOptionsCallback = new IContentCaptureOptionsCallback.Stub() {
|
||||
@Override
|
||||
public void setContentCaptureOptions(ContentCaptureOptions options)
|
||||
throws RemoteException {
|
||||
if (mInitialApplication != null) {
|
||||
mInitialApplication.setContentCaptureOptions(options);
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
service.registerContentCaptureOptionsCallback(packageName,
|
||||
mContentCaptureOptionsCallback);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "registerContentCaptureOptionsCallback() failed: "
|
||||
+ packageName, e);
|
||||
mContentCaptureOptionsCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInstrumentWithoutRestart(AppBindData data) {
|
||||
try {
|
||||
data.compatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.view.contentcapture.ContentCaptureEvent;
|
||||
import android.view.contentcapture.DataRemovalRequest;
|
||||
import android.view.contentcapture.DataShareRequest;
|
||||
import android.view.contentcapture.IDataShareWriteAdapter;
|
||||
import android.view.contentcapture.IContentCaptureOptionsCallback;
|
||||
import android.os.IBinder;
|
||||
import android.os.ICancellationSignal;
|
||||
|
||||
@@ -101,4 +102,10 @@ oneway interface IContentCaptureManager {
|
||||
* Sets whether the default service should be used.
|
||||
*/
|
||||
void setDefaultServiceEnabled(int userId, boolean enabled);
|
||||
|
||||
/**
|
||||
* Registers a listener to handle updates ContentCaptureOptions from server.
|
||||
*/
|
||||
void registerContentCaptureOptionsCallback(String packageName,
|
||||
in IContentCaptureOptionsCallback callback);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2021, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view.contentcapture;
|
||||
|
||||
import android.content.ContentCaptureOptions;
|
||||
|
||||
/**
|
||||
* Callback for changes to content capture options made by ContentCaptureService.
|
||||
* Callback interface used by IContentCaptureManager to send asynchronous
|
||||
* notifications back to its clients. Note that this is a
|
||||
* one-way interface so the server does not block waiting for the client.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IContentCaptureOptionsCallback {
|
||||
void setContentCaptureOptions(in ContentCaptureOptions options);
|
||||
}
|
||||
@@ -98,6 +98,18 @@ public class GlobalWhitelistState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets packages that are either entirely allowlisted or have components that are allowlisted
|
||||
* for the given user.
|
||||
*/
|
||||
public ArraySet<String> getWhitelistedPackages(@UserIdInt int userId) {
|
||||
synchronized (mGlobalWhitelistStateLock) {
|
||||
if (mWhitelisterHelpers == null) return null;
|
||||
final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
|
||||
return helper == null ? null : helper.getWhitelistedPackages();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the allowlist for the given user.
|
||||
*/
|
||||
|
||||
@@ -140,6 +140,15 @@ public final class WhitelistHelper {
|
||||
return mWhitelistedPackages == null ? null : mWhitelistedPackages.get(packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of all packages that are either entirely allowlisted or have components that
|
||||
* are allowlisted.
|
||||
*/
|
||||
@Nullable
|
||||
public ArraySet<String> getWhitelistedPackages() {
|
||||
return mWhitelistedPackages == null ? null : new ArraySet<>(mWhitelistedPackages.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WhitelistHelper[" + mWhitelistedPackages + ']';
|
||||
|
||||
@@ -69,6 +69,7 @@ import android.provider.Settings;
|
||||
import android.service.contentcapture.ActivityEvent.ActivityEventType;
|
||||
import android.service.contentcapture.IDataShareCallback;
|
||||
import android.service.contentcapture.IDataShareReadAdapter;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.LocalLog;
|
||||
import android.util.Pair;
|
||||
@@ -81,6 +82,7 @@ import android.view.contentcapture.ContentCaptureManager;
|
||||
import android.view.contentcapture.DataRemovalRequest;
|
||||
import android.view.contentcapture.DataShareRequest;
|
||||
import android.view.contentcapture.IContentCaptureManager;
|
||||
import android.view.contentcapture.IContentCaptureOptionsCallback;
|
||||
import android.view.contentcapture.IDataShareWriteAdapter;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -134,6 +136,9 @@ public final class ContentCaptureManagerService extends
|
||||
|
||||
private final LocalService mLocalService = new LocalService();
|
||||
|
||||
private final ContentCaptureManagerServiceStub mContentCaptureManagerServiceStub =
|
||||
new ContentCaptureManagerServiceStub();
|
||||
|
||||
@Nullable
|
||||
final LocalLog mRequestsHistory;
|
||||
|
||||
@@ -224,8 +229,7 @@ public final class ContentCaptureManagerService extends
|
||||
|
||||
@Override // from SystemService
|
||||
public void onStart() {
|
||||
publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE,
|
||||
new ContentCaptureManagerServiceStub());
|
||||
publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE, mContentCaptureManagerServiceStub);
|
||||
publishLocalService(ContentCaptureManagerInternal.class, mLocalService);
|
||||
}
|
||||
|
||||
@@ -492,6 +496,19 @@ public final class ContentCaptureManagerService extends
|
||||
}
|
||||
}
|
||||
|
||||
void updateOptions(String packageName, ContentCaptureOptions options) {
|
||||
ArraySet<CallbackRecord> records;
|
||||
synchronized (mLock) {
|
||||
records = mContentCaptureManagerServiceStub.mCallbacks.get(packageName);
|
||||
if (records != null) {
|
||||
int N = records.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
records.valueAt(i).setContentCaptureOptions(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ActivityManagerInternal getAmInternal() {
|
||||
synchronized (mLock) {
|
||||
if (mAm == null) {
|
||||
@@ -599,6 +616,8 @@ public final class ContentCaptureManagerService extends
|
||||
}
|
||||
|
||||
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayMap<String, ArraySet<CallbackRecord>> mCallbacks = new ArrayMap<>();
|
||||
|
||||
@Override
|
||||
public void startSession(@NonNull IBinder activityToken,
|
||||
@@ -754,6 +773,46 @@ public final class ContentCaptureManagerService extends
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerContentCaptureOptionsCallback(@NonNull String packageName,
|
||||
IContentCaptureOptionsCallback callback) {
|
||||
assertCalledByPackageOwner(packageName);
|
||||
|
||||
CallbackRecord record = new CallbackRecord(callback, packageName);
|
||||
record.registerObserver();
|
||||
|
||||
synchronized (mLock) {
|
||||
ArraySet<CallbackRecord> records = mCallbacks.get(packageName);
|
||||
if (records == null) {
|
||||
records = new ArraySet<>();
|
||||
}
|
||||
records.add(record);
|
||||
mCallbacks.put(packageName, records);
|
||||
}
|
||||
|
||||
// Set options here in case it was updated before this was registered.
|
||||
final int userId = UserHandle.getCallingUserId();
|
||||
final ContentCaptureOptions options = mGlobalContentCaptureOptions.getOptions(userId,
|
||||
packageName);
|
||||
if (options != null) {
|
||||
record.setContentCaptureOptions(options);
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterContentCaptureOptionsCallback(CallbackRecord record) {
|
||||
synchronized (mLock) {
|
||||
ArraySet<CallbackRecord> records = mCallbacks.get(record.mPackageName);
|
||||
if (records != null) {
|
||||
records.remove(record);
|
||||
}
|
||||
|
||||
if (records == null || records.isEmpty()) {
|
||||
mCallbacks.remove(record.mPackageName);
|
||||
}
|
||||
}
|
||||
record.unregisterObserver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
|
||||
@@ -1218,4 +1277,39 @@ public final class ContentCaptureManagerService extends
|
||||
mDataShareRequest.getPackageName());
|
||||
}
|
||||
}
|
||||
|
||||
private final class CallbackRecord implements IBinder.DeathRecipient {
|
||||
private final String mPackageName;
|
||||
private final IContentCaptureOptionsCallback mCallback;
|
||||
|
||||
private CallbackRecord(IContentCaptureOptionsCallback callback, String packageName) {
|
||||
mCallback = callback;
|
||||
mPackageName = packageName;
|
||||
}
|
||||
|
||||
private void setContentCaptureOptions(ContentCaptureOptions options) {
|
||||
try {
|
||||
mCallback.setContentCaptureOptions(options);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerObserver() {
|
||||
try {
|
||||
mCallback.asBinder().linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Failed to register callback cleanup " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterObserver() {
|
||||
mCallback.asBinder().unlinkToDeath(this, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
mContentCaptureManagerServiceStub.unregisterContentCaptureOptionsCallback(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,9 +597,15 @@ final class ContentCapturePerUserService
|
||||
? "null_activities" : activities.size() + " activities") + ")"
|
||||
+ " for user " + mUserId);
|
||||
}
|
||||
|
||||
ArraySet<String> oldList =
|
||||
mMaster.mGlobalContentCaptureOptions.getWhitelistedPackages(mUserId);
|
||||
|
||||
mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
|
||||
writeSetWhitelistEvent(getServiceComponentName(), packages, activities);
|
||||
|
||||
updateContentCaptureOptions(oldList);
|
||||
|
||||
// Must disable session that are not the allowlist anymore...
|
||||
final int numSessions = mSessions.size();
|
||||
if (numSessions <= 0) return;
|
||||
@@ -671,5 +677,23 @@ final class ContentCapturePerUserService
|
||||
ContentCaptureMetricsLogger.writeSessionFlush(sessionId, getServiceComponentName(), app,
|
||||
flushMetrics, options, flushReason);
|
||||
}
|
||||
|
||||
/** Updates {@link ContentCaptureOptions} for all newly added packages on allowlist. */
|
||||
private void updateContentCaptureOptions(@Nullable ArraySet<String> oldList) {
|
||||
ArraySet<String> adding = mMaster.mGlobalContentCaptureOptions
|
||||
.getWhitelistedPackages(mUserId);
|
||||
|
||||
if (oldList != null && adding != null) {
|
||||
adding.removeAll(oldList);
|
||||
}
|
||||
|
||||
int N = adding != null ? adding.size() : 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
String packageName = adding.valueAt(i);
|
||||
ContentCaptureOptions options = mMaster.mGlobalContentCaptureOptions
|
||||
.getOptions(mUserId, packageName);
|
||||
mMaster.updateOptions(packageName, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user