Merge "Propagate ContentCaptureManager allowlist update to activities" into sc-dev
This commit is contained in:
@@ -176,6 +176,8 @@ import android.view.Window;
|
|||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.WindowManagerGlobal;
|
import android.view.WindowManagerGlobal;
|
||||||
import android.view.autofill.AutofillId;
|
import android.view.autofill.AutofillId;
|
||||||
|
import android.view.contentcapture.IContentCaptureManager;
|
||||||
|
import android.view.contentcapture.IContentCaptureOptionsCallback;
|
||||||
import android.view.translation.TranslationSpec;
|
import android.view.translation.TranslationSpec;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.window.SplashScreen;
|
import android.window.SplashScreen;
|
||||||
@@ -512,6 +514,8 @@ public final class ActivityThread extends ClientTransactionHandler {
|
|||||||
|
|
||||||
boolean mHasImeComponent = false;
|
boolean mHasImeComponent = false;
|
||||||
|
|
||||||
|
private IContentCaptureOptionsCallback.Stub mContentCaptureOptionsCallback = null;
|
||||||
|
|
||||||
/** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
|
/** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
|
||||||
public static final class ActivityClientRecord {
|
public static final class ActivityClientRecord {
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
@@ -1939,6 +1943,7 @@ public final class ActivityThread extends ClientTransactionHandler {
|
|||||||
public static final int PURGE_RESOURCES = 161;
|
public static final int PURGE_RESOURCES = 161;
|
||||||
public static final int ATTACH_STARTUP_AGENTS = 162;
|
public static final int ATTACH_STARTUP_AGENTS = 162;
|
||||||
public static final int UPDATE_UI_TRANSLATION_STATE = 163;
|
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 INSTRUMENT_WITHOUT_RESTART = 170;
|
||||||
public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171;
|
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 PURGE_RESOURCES: return "PURGE_RESOURCES";
|
||||||
case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
|
case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
|
||||||
case UPDATE_UI_TRANSLATION_STATE: return "UPDATE_UI_TRANSLATION_STATE";
|
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 INSTRUMENT_WITHOUT_RESTART: return "INSTRUMENT_WITHOUT_RESTART";
|
||||||
case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
|
case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
|
||||||
return "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,
|
(TranslationSpec) args.arg3, (TranslationSpec) args.arg4,
|
||||||
(List<AutofillId>) args.arg5);
|
(List<AutofillId>) args.arg5);
|
||||||
break;
|
break;
|
||||||
|
case SET_CONTENT_CAPTURE_OPTIONS_CALLBACK:
|
||||||
|
handleSetContentCaptureOptionsCallback((String) msg.obj);
|
||||||
|
break;
|
||||||
case INSTRUMENT_WITHOUT_RESTART:
|
case INSTRUMENT_WITHOUT_RESTART:
|
||||||
handleInstrumentWithoutRestart((AppBindData) msg.obj);
|
handleInstrumentWithoutRestart((AppBindData) msg.obj);
|
||||||
break;
|
break;
|
||||||
@@ -6795,6 +6805,7 @@ public final class ActivityThread extends ClientTransactionHandler {
|
|||||||
|
|
||||||
// Propagate Content Capture options
|
// Propagate Content Capture options
|
||||||
app.setContentCaptureOptions(data.contentCaptureOptions);
|
app.setContentCaptureOptions(data.contentCaptureOptions);
|
||||||
|
sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName);
|
||||||
|
|
||||||
mInitialApplication = app;
|
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) {
|
private void handleInstrumentWithoutRestart(AppBindData data) {
|
||||||
try {
|
try {
|
||||||
data.compatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
|
data.compatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.view.contentcapture.ContentCaptureEvent;
|
|||||||
import android.view.contentcapture.DataRemovalRequest;
|
import android.view.contentcapture.DataRemovalRequest;
|
||||||
import android.view.contentcapture.DataShareRequest;
|
import android.view.contentcapture.DataShareRequest;
|
||||||
import android.view.contentcapture.IDataShareWriteAdapter;
|
import android.view.contentcapture.IDataShareWriteAdapter;
|
||||||
|
import android.view.contentcapture.IContentCaptureOptionsCallback;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.ICancellationSignal;
|
import android.os.ICancellationSignal;
|
||||||
|
|
||||||
@@ -101,4 +102,10 @@ oneway interface IContentCaptureManager {
|
|||||||
* Sets whether the default service should be used.
|
* Sets whether the default service should be used.
|
||||||
*/
|
*/
|
||||||
void setDefaultServiceEnabled(int userId, boolean enabled);
|
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.
|
* Resets the allowlist for the given user.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -140,6 +140,15 @@ public final class WhitelistHelper {
|
|||||||
return mWhitelistedPackages == null ? null : mWhitelistedPackages.get(packageName);
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "WhitelistHelper[" + mWhitelistedPackages + ']';
|
return "WhitelistHelper[" + mWhitelistedPackages + ']';
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ import android.provider.Settings;
|
|||||||
import android.service.contentcapture.ActivityEvent.ActivityEventType;
|
import android.service.contentcapture.ActivityEvent.ActivityEventType;
|
||||||
import android.service.contentcapture.IDataShareCallback;
|
import android.service.contentcapture.IDataShareCallback;
|
||||||
import android.service.contentcapture.IDataShareReadAdapter;
|
import android.service.contentcapture.IDataShareReadAdapter;
|
||||||
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.LocalLog;
|
import android.util.LocalLog;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -81,6 +82,7 @@ import android.view.contentcapture.ContentCaptureManager;
|
|||||||
import android.view.contentcapture.DataRemovalRequest;
|
import android.view.contentcapture.DataRemovalRequest;
|
||||||
import android.view.contentcapture.DataShareRequest;
|
import android.view.contentcapture.DataShareRequest;
|
||||||
import android.view.contentcapture.IContentCaptureManager;
|
import android.view.contentcapture.IContentCaptureManager;
|
||||||
|
import android.view.contentcapture.IContentCaptureOptionsCallback;
|
||||||
import android.view.contentcapture.IDataShareWriteAdapter;
|
import android.view.contentcapture.IDataShareWriteAdapter;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
@@ -134,6 +136,9 @@ public final class ContentCaptureManagerService extends
|
|||||||
|
|
||||||
private final LocalService mLocalService = new LocalService();
|
private final LocalService mLocalService = new LocalService();
|
||||||
|
|
||||||
|
private final ContentCaptureManagerServiceStub mContentCaptureManagerServiceStub =
|
||||||
|
new ContentCaptureManagerServiceStub();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
final LocalLog mRequestsHistory;
|
final LocalLog mRequestsHistory;
|
||||||
|
|
||||||
@@ -224,8 +229,7 @@ public final class ContentCaptureManagerService extends
|
|||||||
|
|
||||||
@Override // from SystemService
|
@Override // from SystemService
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE,
|
publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE, mContentCaptureManagerServiceStub);
|
||||||
new ContentCaptureManagerServiceStub());
|
|
||||||
publishLocalService(ContentCaptureManagerInternal.class, mLocalService);
|
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() {
|
private ActivityManagerInternal getAmInternal() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (mAm == null) {
|
if (mAm == null) {
|
||||||
@@ -599,6 +616,8 @@ public final class ContentCaptureManagerService extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
|
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private final ArrayMap<String, ArraySet<CallbackRecord>> mCallbacks = new ArrayMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startSession(@NonNull IBinder activityToken,
|
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
|
@Override
|
||||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
|
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
|
||||||
@@ -1218,4 +1277,39 @@ public final class ContentCaptureManagerService extends
|
|||||||
mDataShareRequest.getPackageName());
|
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") + ")"
|
? "null_activities" : activities.size() + " activities") + ")"
|
||||||
+ " for user " + mUserId);
|
+ " for user " + mUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArraySet<String> oldList =
|
||||||
|
mMaster.mGlobalContentCaptureOptions.getWhitelistedPackages(mUserId);
|
||||||
|
|
||||||
mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
|
mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
|
||||||
writeSetWhitelistEvent(getServiceComponentName(), packages, activities);
|
writeSetWhitelistEvent(getServiceComponentName(), packages, activities);
|
||||||
|
|
||||||
|
updateContentCaptureOptions(oldList);
|
||||||
|
|
||||||
// Must disable session that are not the allowlist anymore...
|
// Must disable session that are not the allowlist anymore...
|
||||||
final int numSessions = mSessions.size();
|
final int numSessions = mSessions.size();
|
||||||
if (numSessions <= 0) return;
|
if (numSessions <= 0) return;
|
||||||
@@ -671,5 +677,23 @@ final class ContentCapturePerUserService
|
|||||||
ContentCaptureMetricsLogger.writeSessionFlush(sessionId, getServiceComponentName(), app,
|
ContentCaptureMetricsLogger.writeSessionFlush(sessionId, getServiceComponentName(), app,
|
||||||
flushMetrics, options, flushReason);
|
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