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

Commit bc6b6fee authored by Evan Severson's avatar Evan Severson
Browse files

[AppOps] Remove unwanted UidState objects more quickly

We have more modern ways to query a snapshot of packages on the device,
in fact we have already been using this so we can apply it to other work
that we do where we need to remove or update UidStates objects that may
represent packages that no longer exist or are outdated.

Bug: 320850079
Test: Boot and verify improvement in this logcat "SystemServerTiming:
        PhaseActivityManagerReady took to complete:"

Change-Id: Ic4011b8ecb45aee97ca08d85220f6892bd07fa6f
parent ba33a165
Loading
Loading
Loading
Loading
+101 −107
Original line number Diff line number Diff line
@@ -164,7 +164,6 @@ import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemServiceManager;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.pm.PackageList;
@@ -1046,69 +1045,8 @@ public class AppOpsService extends IAppOpsService.Stub {
                    return;
                }

                ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
                ArraySet<String> attributionTags = new ArraySet<>();
                attributionTags.add(null);
                if (pkg.getAttributions() != null) {
                    int numAttributions = pkg.getAttributions().size();
                    for (int attributionNum = 0; attributionNum < numAttributions;
                            attributionNum++) {
                        ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
                        attributionTags.add(attribution.getTag());

                        int numInheritFrom = attribution.getInheritFrom().size();
                        for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
                                inheritFromNum++) {
                            dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
                                    attribution.getTag());
                        }
                    }
                }

                synchronized (AppOpsService.this) {
                    UidState uidState = mUidStates.get(uid);
                    if (uidState == null) {
                        return;
                    }

                    Ops ops = uidState.pkgOps.get(pkgName);
                    if (ops == null) {
                        return;
                    }

                    // Reset cached package properties to re-initialize when needed
                    ops.bypass = null;
                    ops.knownAttributionTags.clear();

                    // Merge data collected for removed attributions into their successor
                    // attributions
                    int numOps = ops.size();
                    for (int opNum = 0; opNum < numOps; opNum++) {
                        Op op = ops.valueAt(opNum);
                        for (int deviceIndex = op.mDeviceAttributedOps.size() - 1; deviceIndex >= 0;
                                deviceIndex--) {
                            ArrayMap<String, AttributedOp> attributedOps =
                                    op.mDeviceAttributedOps.valueAt(deviceIndex);
                            for (int tagIndex = attributedOps.size() - 1; tagIndex >= 0;
                                    tagIndex--) {
                                String tag = attributedOps.keyAt(tagIndex);
                                if (attributionTags.contains(tag)) {
                                    // attribution still exist after upgrade
                                    continue;
                                }

                                String newAttributionTag = dstAttributionTags.get(tag);

                                AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
                                        newAttributionTag,
                                        op.mDeviceAttributedOps.keyAt(deviceIndex));
                                newAttributedOp.add(attributedOps.get(tag));
                                attributedOps.remove(tag);

                                scheduleFastWriteLocked();
                            }
                        }
                    }
                    refreshAttributionsLocked(pkg, uid);
                }
            }
        }
@@ -1132,41 +1070,6 @@ public class AppOpsService extends IAppOpsService.Stub {
        mContext.registerReceiverAsUser(mOnPackageUpdatedReceiver, UserHandle.ALL,
                packageUpdateFilter, null, null);

        synchronized (this) {
            for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
                int uid = mUidStates.keyAt(uidNum);
                UidState uidState = mUidStates.valueAt(uidNum);

                String[] pkgsInUid = getPackagesForUid(uidState.uid);
                if (ArrayUtils.isEmpty(pkgsInUid) && uid >= Process.FIRST_APPLICATION_UID) {
                    uidState.clear();
                    mUidStates.removeAt(uidNum);
                    scheduleFastWriteLocked();
                    continue;
                }

                ArrayMap<String, Ops> pkgs = uidState.pkgOps;

                int numPkgs = pkgs.size();
                for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
                    String pkg = pkgs.keyAt(pkgNum);

                    String action;
                    if (!ArrayUtils.contains(pkgsInUid, pkg)) {
                        action = ACTION_PACKAGE_REMOVED;
                    } else {
                        action = Intent.ACTION_PACKAGE_REPLACED;
                    }

                    SystemServerInitThreadPool.submit(
                            () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
                                    .setData(Uri.fromParts("package", pkg, null))
                                    .putExtra(Intent.EXTRA_UID, uid)),
                            "Update app-ops uidState in case package " + pkg + " changed");
                }
            }
        }

        prepareInternalCallbacks();

        final IntentFilter packageSuspendFilter = new IntentFilter();
@@ -1270,19 +1173,12 @@ public class AppOpsService extends IAppOpsService.Stub {
                    int userId = userIds[i];
                    initializeUserUidStatesLocked(userId, packageStates, knownUids);
                }
            }

            // Remove what may have been added during persistence parsing
            for (int i = mUidStates.size() - 1; i >= 0; i--) {
                int uid = mUidStates.keyAt(i);
                if (!knownUids.get(uid, false)) {
                    mUidStates.removeAt(i);
                }
            }

                trimUidStatesLocked(knownUids, packageStates);
                mUidStatesInitialized = true;
            }
        }
    }

    private void initializeUserUidStates(int userId) {
        synchronized (this) {
@@ -1336,6 +1232,104 @@ public class AppOpsService extends IAppOpsService.Stub {
        createSandboxUidStateIfNotExistsForAppLocked(uid, knownUids);
    }

    private void trimUidStatesLocked(SparseBooleanArray knownUids,
            Map<String, PackageState> packageStates) {
        synchronized (this) {
            // Remove what may have been added during persistence parsing
            for (int i = mUidStates.size() - 1; i >= 0; i--) {
                int uid = mUidStates.keyAt(i);
                if (knownUids.get(uid, false)) {
                    if (uid >= Process.FIRST_APPLICATION_UID) {
                        ArrayMap<String, Ops> pkgOps = mUidStates.valueAt(i).pkgOps;
                        for (int j = 0; j < pkgOps.size(); j++) {
                            String pkgName = pkgOps.keyAt(j);
                            if (!packageStates.containsKey(pkgName)) {
                                pkgOps.removeAt(j);
                                continue;
                            }
                            AndroidPackage pkg = packageStates.get(pkgName).getAndroidPackage();
                            if (pkg != null) {
                                refreshAttributionsLocked(pkg, uid);
                            }
                        }
                        if (pkgOps.isEmpty()) {
                            mUidStates.remove(i);
                        }
                    }
                } else {
                    mUidStates.removeAt(i);
                }
            }
        }
    }

    @GuardedBy("this")
    private void refreshAttributionsLocked(AndroidPackage pkg, int uid) {
        String pkgName = pkg.getPackageName();
        ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
        ArraySet<String> attributionTags = new ArraySet<>();
        attributionTags.add(null);
        if (pkg.getAttributions() != null) {
            int numAttributions = pkg.getAttributions().size();
            for (int attributionNum = 0; attributionNum < numAttributions;
                    attributionNum++) {
                ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
                attributionTags.add(attribution.getTag());

                int numInheritFrom = attribution.getInheritFrom().size();
                for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
                        inheritFromNum++) {
                    dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
                            attribution.getTag());
                }
            }
        }

        UidState uidState = mUidStates.get(uid);
        if (uidState == null) {
            return;
        }

        Ops ops = uidState.pkgOps.get(pkgName);
        if (ops == null) {
            return;
        }

        // Reset cached package properties to re-initialize when needed
        ops.bypass = null;
        ops.knownAttributionTags.clear();

        // Merge data collected for removed attributions into their successor
        // attributions
        int numOps = ops.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            Op op = ops.valueAt(opNum);
            for (int deviceIndex = op.mDeviceAttributedOps.size() - 1; deviceIndex >= 0;
                    deviceIndex--) {
                ArrayMap<String, AttributedOp> attributedOps =
                        op.mDeviceAttributedOps.valueAt(deviceIndex);
                for (int tagIndex = attributedOps.size() - 1; tagIndex >= 0;
                        tagIndex--) {
                    String tag = attributedOps.keyAt(tagIndex);
                    if (attributionTags.contains(tag)) {
                        // attribution still exist after upgrade
                        continue;
                    }

                    String newAttributionTag = dstAttributionTags.get(tag);

                    AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
                            newAttributionTag,
                            op.mDeviceAttributedOps.keyAt(deviceIndex));
                    newAttributedOp.add(attributedOps.get(tag));
                    attributedOps.remove(tag);

                    scheduleFastWriteLocked();
                }
            }
        }
    }

    /**
     * Sets a policy for handling app ops.
     *