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

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

Merge "Fixed ContentCapture and AugmentedAutofill methods that should not hold the main lock..."

parents bf92d73a 9bee9440
Loading
Loading
Loading
Loading
+131 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 com.android.internal.infra;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.util.ArraySet;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;

import java.io.PrintWriter;
import java.util.List;

/**
 * Helper class used to manage a {@link WhitelistHelper} per user instance when the main service
 * cannot hold a lock when external entities (typically {@code ActivityManagerService}) needs to
 * get whitelist info.
 *
 * <p>This class is thread safe.
 */
public class GlobalWhitelistState {

    // Uses full-name to avoid collision with service-provided mLock
    protected final Object mGlobalWhitelistStateLock = new Object();

    @Nullable
    @GuardedBy("mGlobalWhitelistStateLock")
    protected SparseArray<WhitelistHelper> mWhitelisterHelpers;

    /**
     * Sets the whitelist for the given user.
     */
    public void setWhitelist(@UserIdInt int userId, @Nullable List<String> packageNames,
            @Nullable List<ComponentName> components) {
        synchronized (mGlobalWhitelistStateLock) {
            if (mWhitelisterHelpers == null) {
                mWhitelisterHelpers = new SparseArray<>(1);
            }
            WhitelistHelper helper = mWhitelisterHelpers.get(userId);
            if (helper == null) {
                helper = new WhitelistHelper();
                mWhitelisterHelpers.put(userId, helper);
            }
            helper.setWhitelist(packageNames, components);
        }
    }

    /**
     * Checks if the given package is whitelisted for the given user.
     */
    public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) {
        synchronized (mGlobalWhitelistStateLock) {
            if (mWhitelisterHelpers == null) return false;
            final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
            return helper == null ? false : helper.isWhitelisted(packageName);
        }
    }

    /**
     * Checks if the given component is whitelisted for the given user.
     */
    public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) {
        synchronized (mGlobalWhitelistStateLock) {
            if (mWhitelisterHelpers == null) return false;
            final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
            return helper == null ? false : helper.isWhitelisted(componentName);
        }
    }

    /**
     * Gets the whitelisted components for the given package and user.
     */
    public ArraySet<ComponentName> getWhitelistedComponents(@UserIdInt int userId,
            @NonNull String packageName) {
        synchronized (mGlobalWhitelistStateLock) {
            if (mWhitelisterHelpers == null) return null;
            final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
            return helper == null ? null : helper.getWhitelistedComponents(packageName);
        }
    }

    /**
     * Resets the whitelist for the given user.
     */
    public void resetWhitelist(@NonNull int userId) {
        synchronized (mGlobalWhitelistStateLock) {
            if (mWhitelisterHelpers == null) return;
            mWhitelisterHelpers.remove(userId);
            if (mWhitelisterHelpers.size() == 0) {
                mWhitelisterHelpers = null;
            }
        }
    }

    /**
     * Dumps it!
     */
    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
        pw.print(prefix); pw.print("State: ");
        synchronized (mGlobalWhitelistStateLock) {
            if (mWhitelisterHelpers == null) {
                pw.println("empty");
                return;
            }
            pw.print(mWhitelisterHelpers.size()); pw.println(" services");
            final String prefix2 = prefix + "  ";
            for (int i = 0; i < mWhitelisterHelpers.size(); i++) {
                final int userId  = mWhitelisterHelpers.keyAt(i);
                final WhitelistHelper helper = mWhitelisterHelpers.valueAt(i);
                helper.dump(prefix2, "Whitelist for userId " + userId, pw);
            }
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import java.util.List;
/**
 * Helper class for keeping track of whitelisted packages/activities.
 *
 * <p><b>NOTE: </b>this class is not thread safe.
 * @hide
 */
public final class WhitelistHelper {
+110 −13
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
@@ -61,6 +62,7 @@ import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -72,6 +74,8 @@ import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.GlobalWhitelistState;
import com.android.internal.infra.WhitelistHelper;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
@@ -146,6 +150,7 @@ public final class AutofillManagerService
    private final LocalLog mWtfHistory = new LocalLog(50);

    private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();

    private final LocalService mLocalService = new LocalService();
    private final ActivityManagerInternal mAm;

@@ -178,6 +183,8 @@ public final class AutofillManagerService
    @GuardedBy("mLock")
    int mAugmentedServiceRequestTimeoutMs;

    final AugmentedAutofillState mAugmentedAutofillState = new AugmentedAutofillState();

    public AutofillManagerService(Context context) {
        super(context,
                new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
@@ -187,7 +194,7 @@ public final class AutofillManagerService

        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
                ActivityThread.currentApplication().getMainExecutor(),
                (namespace, key, value) -> onDeviceConfigChange(key, value));
                (namespace, key, value) -> onDeviceConfigChange(key));

        setLogLevelFromSettings();
        setMaxPartitionsFromSettings();
@@ -201,15 +208,20 @@ public final class AutofillManagerService
        mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(getContext(),
                com.android.internal.R.string.config_defaultAugmentedAutofillService);
        mAugmentedAutofillResolver.setOnTemporaryServiceNameChangedCallback(
                (u, s) -> getServiceForUserLocked(u).updateRemoteAugmentedAutofillService());
                (u, s, t) -> onAugmentedServiceNameChanged(u, s, t));

        if (mSupportedSmartSuggestionModes != AutofillManager.FLAG_SMART_SUGGESTION_OFF) {
            // Must eager load the services so they bind to the augmented autofill service
            final UserManager um = getContext().getSystemService(UserManager.class);
            final List<UserInfo> users = um.getUsers();
            for (int i = 0; i < users.size(); i++) {
                final int userId = users.get(i).id;
                // Must eager load the services so they bind to the augmented autofill service
                getServiceForUserLocked(userId);

                // And also set the global state
                mAugmentedAutofillState.setServiceInfo(userId,
                        mAugmentedAutofillResolver.getServiceName(userId),
                        mAugmentedAutofillResolver.isTemporary(userId));
            }
        }
    }
@@ -258,7 +270,7 @@ public final class AutofillManagerService
        }
    }

    private void onDeviceConfigChange(@NonNull String key, @Nullable String value) {
    private void onDeviceConfigChange(@NonNull String key) {
        switch (key) {
            case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
            case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
@@ -270,6 +282,14 @@ public final class AutofillManagerService
        }
    }

    private void onAugmentedServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
            boolean isTemporary) {
        mAugmentedAutofillState.setServiceInfo(userId, serviceName, isTemporary);
        synchronized (mLock) {
            getServiceForUserLocked(userId).updateRemoteAugmentedAutofillService();
        }
    }

    @Override // from AbstractMasterSystemService
    protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
            boolean disabled) {
@@ -783,15 +803,7 @@ public final class AutofillManagerService
            final boolean compatModeEnabled = mAutofillCompatState.isCompatibilityModeRequested(
                    packageName, versionCode, userId);
            final AutofillOptions options = new AutofillOptions(loggingLevel, compatModeEnabled);

            synchronized (mLock) {
                final AutofillManagerServiceImpl service =
                        getServiceForUserLocked(UserHandle.getCallingUserId());
                if (service != null) {
                    service.setAugmentedAutofillWhitelistLocked(options, packageName);
                }
            }

            mAugmentedAutofillState.injectAugmentedAutofillInfo(options, userId, packageName);
            return options;
        }
    }
@@ -934,6 +946,89 @@ public final class AutofillManagerService
        }
    }

    /**
     * Augmented autofill metadata associated with all services.
     *
     * <p>This object is defined here instead of on each {@link AutofillManagerServiceImpl} because
     * it cannot hold a lock on the main lock when
     * {@link AugmentedAutofillState#injectAugmentedAutofillInfo(AutofillOptions, int, String)}
     * is called by external services.
     */
    static final class AugmentedAutofillState extends GlobalWhitelistState {

        @GuardedBy("mGlobalWhitelistStateLock")
        private final SparseArray<String> mServicePackages = new SparseArray<>();
        @GuardedBy("mGlobalWhitelistStateLock")
        private final SparseBooleanArray mTemporaryServices = new SparseBooleanArray();

        private void setServiceInfo(@UserIdInt int userId, @Nullable String serviceName,
                boolean isTemporary) {
            synchronized (mGlobalWhitelistStateLock) {
                if (isTemporary) {
                    mTemporaryServices.put(userId, true);
                } else {
                    mTemporaryServices.delete(userId);
                }
                if (serviceName != null) {
                    final ComponentName componentName =
                            ComponentName.unflattenFromString(serviceName);
                    if (componentName == null) {
                        Slog.w(TAG, "setServiceInfo(): invalid name: " + serviceName);
                        mServicePackages.remove(userId);
                    } else {
                        mServicePackages.put(userId, componentName.getPackageName());
                    }
                } else {
                    mServicePackages.remove(userId);
                }
            }
        }

        public void injectAugmentedAutofillInfo(@NonNull AutofillOptions options,
                @UserIdInt int userId, @NonNull String packageName) {
            synchronized (mGlobalWhitelistStateLock) {
                if (mWhitelisterHelpers == null) return;
                final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
                if (helper != null) {
                    options.augmentedAutofillEnabled = helper.isWhitelisted(packageName);
                    options.whitelistedActivitiesForAugmentedAutofill = helper
                            .getWhitelistedComponents(packageName);
                }
            }
        }

        @Override
        public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) {
            synchronized (mGlobalWhitelistStateLock) {
                if (!super.isWhitelisted(userId, componentName)) return false;

                if (Build.IS_USER && mTemporaryServices.get(userId)) {
                    final String packageName = componentName.getPackageName();
                    if (!packageName.equals(mServicePackages.get(userId))) {
                        Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill "
                                + "while using temporary service " + mServicePackages.get(userId));
                        return false;
                    }
                }
            }
            return true;
        }

        @Override
        public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
            super.dump(prefix, pw);

            synchronized (mGlobalWhitelistStateLock) {
                if (mServicePackages.size() > 0) {
                    pw.print(prefix); pw.print("Service packages: "); pw.println(mServicePackages);
                }
                if (mTemporaryServices.size() > 0) {
                    pw.print(prefix); pw.print("Temp services: "); pw.println(mTemporaryServices);
                }
            }
        }
    }

    final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
        @Override
        public void addClient(IAutoFillManagerClient client, ComponentName componentName,
@@ -1370,6 +1465,8 @@ public final class AutofillManagerService
                        pw.println(); pw.println("WTF history:"); pw.println();
                        mWtfHistory.reverseDump(fd, pw, args);
                    }
                    pw.println("Augmented Autofill State: ");
                    mAugmentedAutofillState.dump(prefix, pw);
                }
            } finally {
                sDebug = realDebug;
+3 −34
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.content.AutofillOptions;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -40,7 +39,6 @@ import android.graphics.Rect;
import android.metrics.LogMaker;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -76,7 +74,6 @@ import android.view.autofill.IAutoFillManagerClient;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.WhitelistHelper;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
@@ -170,12 +167,6 @@ final class AutofillManagerServiceImpl
    @Nullable
    private ServiceInfo mRemoteAugmentedAutofillServiceInfo;

    /**
     * List of packages/activities that are whitelisted to be trigger augmented autofill.
     */
    @GuardedBy("mLock")
    private final WhitelistHelper mAugmentedWhitelistHelper = new WhitelistHelper();

    AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
            LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
            AutofillCompatState autofillCompatState,
@@ -951,8 +942,6 @@ final class AutofillManagerServiceImpl
            pw.println(mRemoteAugmentedAutofillServiceInfo);
        }

        mAugmentedWhitelistHelper.dump(prefix, "Augmented autofill whitelist", pw);

        pw.print(prefix); pw.print("Field classification enabled: ");
            pw.println(isFieldClassificationEnabledLocked());
        pw.print(prefix); pw.print("Compat pkgs: ");
@@ -1234,27 +1223,7 @@ final class AutofillManagerServiceImpl

    @GuardedBy("mLock")
    boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
        if (Build.IS_USER && mMaster.mAugmentedAutofillResolver.isTemporary(mUserId)) {
            final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
            final ComponentName component = ComponentName.unflattenFromString(serviceName);
            final String servicePackage = component == null ? null : component.getPackageName();
            final String packageName = componentName.getPackageName();
            if (!packageName.equals(servicePackage)) {
                Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill while "
                        + "using temporary service " + servicePackage);
                return false;
            }
        }

        return mAugmentedWhitelistHelper.isWhitelisted(componentName);
    }

    @GuardedBy("mLock")
    void setAugmentedAutofillWhitelistLocked(@NonNull AutofillOptions options,
            @NonNull String packageName) {
        options.augmentedAutofillEnabled = mAugmentedWhitelistHelper.isWhitelisted(packageName);
        options.whitelistedActivitiesForAugmentedAutofill = mAugmentedWhitelistHelper
                .getWhitelistedComponents(packageName);
        return mMaster.mAugmentedAutofillState.isWhitelisted(mUserId, componentName);
    }

    /**
@@ -1268,7 +1237,7 @@ final class AutofillManagerServiceImpl
            if (mMaster.verbose) {
                Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components);
            }
            mAugmentedWhitelistHelper.setWhitelist(packages, components);
            mMaster.mAugmentedAutofillState.setWhitelist(mUserId, packages, components);
        }
    }

@@ -1280,7 +1249,7 @@ final class AutofillManagerServiceImpl
        if (mMaster.verbose) {
            Slog.v(TAG, "resetting augmented autofill whitelist");
        }
        whitelistForAugmentedAutofillPackages(null, null);
        mMaster.mAugmentedAutofillState.resetWhitelist(mUserId);
    }

    private void sendStateToClients(boolean resetClient) {
+111 −8

File changed.

Preview size limit exceeded, changes collapsed.

Loading