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

Commit a6ebff0f authored by Svetoslav Ganov's avatar Svetoslav Ganov
Browse files

Don't hold the autofill lock when looking up fill compat packages

Test: cts-tradefed run cts-dev -m CtsAutoFillServiceTestCases

Bug:73072565

Change-Id: I773e1e2f4ceedbe45c9389a065dc7f6fb0ab65b1
parent 581576ef
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -11382,7 +11382,8 @@ public final class Settings {
                "chained_battery_attribution_enabled";

        /**
         * The packages whitelisted to be run in autofill compatibility mode.
         * The packages whitelisted to be run in autofill compatibility mode. The list
         * of packages is ":" colon delimited.
         *
         * @hide
         */
+6 −14
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

/**
 * {@link ServiceInfo} and meta-data about an {@link AutofillService}.
@@ -80,7 +79,7 @@ public final class AutofillServiceInfo {
    private final String mSettingsActivity;

    @Nullable
    private final Map<String, Pair<Long, String>> mCompatibilityPackages;
    private final ArrayMap<String, Pair<Long, String>> mCompatibilityPackages;

    public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
            throws PackageManager.NameNotFoundException {
@@ -118,7 +117,7 @@ public final class AutofillServiceInfo {
        }

        String settingsActivity = null;
        Map<String, Pair<Long, String>> compatibilityPackages = null;
        ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;

        try {
            final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -154,10 +153,10 @@ public final class AutofillServiceInfo {
        mCompatibilityPackages = compatibilityPackages;
    }

    private Map<String, Pair<Long, String>> parseCompatibilityPackages(XmlPullParser parser,
    private ArrayMap<String, Pair<Long, String>> parseCompatibilityPackages(XmlPullParser parser,
            Resources resources)
            throws IOException, XmlPullParserException {
        Map<String, Pair<Long, String>> compatibilityPackages = null;
        ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;

        final int outerDepth = parser.getDepth();
        int type;
@@ -229,15 +228,8 @@ public final class AutofillServiceInfo {
        return mSettingsActivity;
    }

    public boolean isCompatibilityModeRequested(String packageName, long versionCode) {
        if (mCompatibilityPackages == null) {
            return false;
        }
        final Pair<Long, String> pair = mCompatibilityPackages.get(packageName);
        if (pair == null) {
            return false;
        }
        return versionCode <= pair.first;
    public ArrayMap<String, Pair<Long, String>> getCompatibilityPackages() {
        return mCompatibilityPackages;
    }

    /**
+112 −8
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sPartitionMaxCount;
import static com.android.server.autofill.Helper.sVerbose;

import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -56,7 +55,12 @@ import android.os.UserManagerInternal;
import android.provider.Settings;
import android.service.autofill.FillEventHistory;
import android.service.autofill.UserData;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -84,6 +88,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * Entry point service for autofill management.
@@ -98,6 +103,8 @@ public final class AutofillManagerService extends SystemService {

    static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";

    private static final char COMPAT_PACKAGE_DELIMITER = ':';

    private final Context mContext;
    private final AutoFillUI mUi;

@@ -123,6 +130,9 @@ public final class AutofillManagerService extends SystemService {
    private final LocalLog mUiLatencyHistory = new LocalLog(20);
    private final LocalLog mWtfHistory = new LocalLog(50);

    private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
    private final LocalService mLocalService = new LocalService();

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
@@ -271,7 +281,7 @@ public final class AutofillManagerService extends SystemService {
    @Override
    public void onStart() {
        publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
        publishLocalService(AutofillManagerInternal.class, new LocalService());
        publishLocalService(AutofillManagerInternal.class, mLocalService);
    }

    @Override
@@ -317,6 +327,11 @@ public final class AutofillManagerService extends SystemService {
                    mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
                    mDisabledUsers.get(resolvedUserId));
            mServicesCache.put(userId, service);
            final ArrayMap<String, Pair<Long, String>> compatPackages =
                    service.getCompatibilityPackagesLocked();
            if (compatPackages != null) {
                addCompatibilityModeRequests(compatPackages, userId);
            }
        }
        return service;
    }
@@ -482,6 +497,7 @@ public final class AutofillManagerService extends SystemService {
        if (service != null) {
            mServicesCache.delete(userId);
            service.destroyLocked();
            mAutofillCompatState.removeCompatibilityModeRequests(userId);
        }
    }

@@ -498,18 +514,60 @@ public final class AutofillManagerService extends SystemService {
     */
    @GuardedBy("mLock")
    private void updateCachedServiceLocked(int userId, boolean disabled) {
        AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
        AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
        if (service != null) {
            service.destroySessionsLocked();
            service.updateLocked(disabled);
            if (!service.isEnabledLocked()) {
                removeCachedServiceLocked(userId);
            } else {
                final ArrayMap<String, Pair<Long, String>> compatPackages =
                        service.getCompatibilityPackagesLocked();
                if (compatPackages != null) {
                    addCompatibilityModeRequests(compatPackages, userId);
                }
            }
        }
    }

    private final class LocalService extends AutofillManagerInternal {
    private void addCompatibilityModeRequests(
            @NonNull ArrayMap<String, Pair<Long, String>> compatPackages, int userId) {
        final Set<String> whiteListedPackages = Build.IS_ENG ? null
                : getWhitelistedCompatModePackages();
        final int compatPackageCount = compatPackages.size();
        for (int i = 0; i < compatPackageCount; i++) {
            final String packageName = compatPackages.keyAt(i);
            if (!Build.IS_ENG && (whiteListedPackages == null
                    || !whiteListedPackages.contains(packageName))) {
                Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
                continue;
            }
            final Long maxVersionCode = compatPackages.valueAt(i).first;
            if (maxVersionCode != null) {
                mAutofillCompatState.addCompatibilityModeRequest(packageName,
                        maxVersionCode, userId);
            }
        }
    }

    private @Nullable Set<String> getWhitelistedCompatModePackages() {
        final String compatPackagesSetting = Settings.Global.getString(
                mContext.getContentResolver(),
                Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
        if (TextUtils.isEmpty(compatPackagesSetting)) {
            return null;
        }
        final Set<String> compatPackages = new ArraySet<>();
        final SimpleStringSplitter splitter = new SimpleStringSplitter(
                COMPAT_PACKAGE_DELIMITER);
        splitter.setString(compatPackagesSetting);
        while (splitter.hasNext()) {
            compatPackages.add(splitter.next());
        }
        return compatPackages;
    }

    private final class LocalService extends AutofillManagerInternal {
        @Override
        public void onBackKeyPressed() {
            if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
@@ -519,14 +577,60 @@ public final class AutofillManagerService extends SystemService {
        @Override
        public boolean isCompatibilityModeRequested(@NonNull String packageName,
                long versionCode, @UserIdInt int userId) {
            return mAutofillCompatState.isCompatibilityModeRequested(
                    packageName, versionCode, userId);
        }
    }

    private static class AutofillCompatState {
        private final Object mLock = new Object();

        @GuardedBy("mLock")
        private SparseArray<ArrayMap<String, Long>> mUserSpecs;

        boolean isCompatibilityModeRequested(@NonNull String packageName,
                long versionCode, @UserIdInt int userId) {
            synchronized (mLock) {
                final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
                if (service != null) {
                    return service.isCompatibilityModeRequestedLocked(packageName, versionCode);
                if (mUserSpecs == null) {
                    return false;
                }
                final ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
                if (userSpec == null) {
                    return false;
                }
                final Long maxVersionCode = userSpec.get(packageName);
                if (maxVersionCode == null) {
                    return false;
                }
                return versionCode <= maxVersionCode;
            }
        }

        void addCompatibilityModeRequest(@NonNull String packageName,
                long versionCode, @UserIdInt int userId) {
            synchronized (mLock) {
                if (mUserSpecs == null) {
                    mUserSpecs = new SparseArray<>();
                }
                ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
                if (userSpec == null) {
                    userSpec = new ArrayMap<>();
                    mUserSpecs.put(userId, userSpec);
                }
                userSpec.put(packageName, versionCode);
            }
        }

        void removeCompatibilityModeRequests(@UserIdInt int userId) {
            synchronized (mLock) {
                if (mUserSpecs != null) {
                    mUserSpecs.remove(userId);
                    if (mUserSpecs.size() <= 0) {
                        mUserSpecs = null;
                    }
                }
            }
        }
    }

    final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
+9 −17
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -906,7 +907,10 @@ final class AutofillManagerServiceImpl {
        pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
        pw.print(prefix); pw.print("Field classification enabled: ");
            pw.println(isFieldClassificationEnabledLocked());
        pw.print(prefix); pw.print("Compat pkgs: "); pw.println(getWhitelistedCompatModePackages());
        final ArrayMap<String, Pair<Long, String>> compatPkgs = getCompatibilityPackagesLocked();
        if (compatPkgs != null) {
            pw.print(prefix); pw.print("Compat pkgs: "); pw.println(compatPkgs.keySet());
        }
        pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
        pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);

@@ -1030,23 +1034,11 @@ final class AutofillManagerServiceImpl {
    }

    @GuardedBy("mLock")
    boolean isCompatibilityModeRequestedLocked(@NonNull String packageName,
            long versionCode) {
        if (mInfo == null || !mInfo.isCompatibilityModeRequested(packageName, versionCode)) {
            return false;
        }
        if (!Build.IS_ENG) {
            // TODO: Build a map and watch for settings changes (this is called on app start)
            final String whiteListedPackages = getWhitelistedCompatModePackages();
            return whiteListedPackages != null && whiteListedPackages.contains(packageName);
        }
        return true;
    @Nullable ArrayMap<String, Pair<Long, String>> getCompatibilityPackagesLocked() {
        if (mInfo != null) {
            return mInfo.getCompatibilityPackages();
        }

    private String getWhitelistedCompatModePackages() {
        return Settings.Global.getString(
                mContext.getContentResolver(),
                Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
        return null;
    }

    private void sendStateToClients(boolean resetClient) {