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

Commit 3ddd1a42 authored by Alex Buynytskyy's avatar Alex Buynytskyy
Browse files

Offload IO to Handler thread.

Bug: 252961134
Test: atest PackageManagerSettingsTests
Change-Id: I11de05fe3bc0d79892a45d45412aca266394c548
parent 8e0eb90b
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import static com.android.server.pm.PackageManagerService.PRUNE_UNUSED_STATIC_SH
import static com.android.server.pm.PackageManagerService.SEND_PENDING_BROADCAST;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_LIST;
import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_RESTRICTIONS;
import static com.android.server.pm.PackageManagerService.WRITE_SETTINGS;

import android.content.Intent;
@@ -119,10 +118,7 @@ final class PackageHandler extends Handler {
                }
            } break;
            case WRITE_SETTINGS: {
                mPm.writeSettings();
            } break;
            case WRITE_PACKAGE_RESTRICTIONS: {
                mPm.writePendingRestrictions();
                mPm.writeSettings(/*sync=*/false);
            } break;
            case WRITE_PACKAGE_LIST: {
                mPm.writePackageList(msg.arg1);
+52 −16
Original line number Diff line number Diff line
@@ -558,6 +558,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
    static final char RANDOM_CODEPATH_PREFIX = '-';

    final Handler mHandler;
    final Handler mBackgroundHandler;

    final ProcessLoggingHandler mProcessLoggingHandler;

@@ -873,7 +874,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
    // public static final int UNUSED = 5;
    static final int POST_INSTALL = 9;
    static final int WRITE_SETTINGS = 13;
    static final int WRITE_PACKAGE_RESTRICTIONS = 14;
    static final int WRITE_DIRTY_PACKAGE_RESTRICTIONS = 14;
    static final int PACKAGE_VERIFIED = 15;
    static final int CHECK_PENDING_VERIFICATION = 16;
    // public static final int UNUSED = 17;
@@ -890,6 +891,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
    static final int PRUNE_UNUSED_STATIC_SHARED_LIBRARIES = 28;
    static final int DEFERRED_PENDING_KILL_INSTALL_OBSERVER = 29;

    static final int WRITE_USER_PACKAGE_RESTRICTIONS = 30;

    static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000;
    private static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
    private static final int DEFERRED_PENDING_KILL_INSTALL_OBSERVER_DELAY_MS = 1000;
@@ -1397,28 +1400,33 @@ public class PackageManagerService implements PackageSender, TestUtilityService
                mDirtyUsers.add(userId);
            }
        }
        if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
            mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
        if (!mBackgroundHandler.hasMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS)) {
            mBackgroundHandler.sendMessageDelayed(
                    mBackgroundHandler.obtainMessage(WRITE_DIRTY_PACKAGE_RESTRICTIONS, this),
                    WRITE_SETTINGS_DELAY);
        }
    }

    void writePendingRestrictions() {
        final Integer[] dirtyUsers;
        synchronized (mLock) {
            mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
            mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS);
            synchronized (mDirtyUsers) {
                for (int userId : mDirtyUsers) {
                    mSettings.writePackageRestrictionsLPr(userId);
                if (mDirtyUsers.isEmpty()) {
                    return;
                }
                dirtyUsers = mDirtyUsers.toArray(Integer[]::new);
                mDirtyUsers.clear();
            }
        }
        mSettings.writePackageRestrictions(dirtyUsers);
    }

    void writeSettings() {
    void writeSettings(boolean sync) {
        synchronized (mLock) {
            mHandler.removeMessages(WRITE_SETTINGS);
            mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
            writeSettingsLPrTEMP();
            mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS);
            writeSettingsLPrTEMP(sync);
            synchronized (mDirtyUsers) {
                mDirtyUsers.clear();
            }
@@ -1432,6 +1440,25 @@ public class PackageManagerService implements PackageSender, TestUtilityService
        }
    }

    private static final Handler.Callback BACKGROUND_HANDLER_CALLBACK = new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case WRITE_DIRTY_PACKAGE_RESTRICTIONS: {
                    PackageManagerService pm = (PackageManagerService) msg.obj;
                    pm.writePendingRestrictions();
                    return true;
                }
                case WRITE_USER_PACKAGE_RESTRICTIONS: {
                    final Runnable r = (Runnable) msg.obj;
                    r.run();
                    return true;
                }
            }
            return false;
        }
    };

    public static Pair<PackageManagerService, IPackageManager> main(Context context,
            Installer installer, @NonNull DomainVerificationService domainVerificationService,
            boolean factoryTest) {
@@ -1446,7 +1473,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
        HandlerThread backgroundThread = new ServiceThread("PackageManagerBg",
                Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
        backgroundThread.start();
        Handler backgroundHandler = new Handler(backgroundThread.getLooper());
        Handler backgroundHandler = new Handler(backgroundThread.getLooper(),
                BACKGROUND_HANDLER_CALLBACK);

        PackageManagerServiceInjector injector = new PackageManagerServiceInjector(
                context, lock, installer, installLock, new PackageAbiHelperImpl(),
@@ -1460,7 +1488,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
                (i, pm) -> new Settings(Environment.getDataDirectory(),
                        RuntimePermissionsPersistence.createInstance(),
                        i.getPermissionManagerServiceInternal(),
                        domainVerificationService, backgroundHandler, lock),
                        domainVerificationService, backgroundHandler,
                        lock),
                (i, pm) -> AppsFilterImpl.create(i,
                        i.getLocalService(PackageManagerInternal.class)),
                (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
@@ -1638,6 +1667,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
        mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
        mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
        mHandler = injector.getHandler();
        mBackgroundHandler = injector.getBackgroundHandler();
        mSharedLibraries = injector.getSharedLibrariesImpl();

        mApexManager = testParams.apexManager;
@@ -1828,6 +1858,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
        mMoveCallbacks = new MovePackageHelper.MoveCallbacks(FgThread.get().getLooper());
        mViewCompiler = injector.getViewCompiler();
        mSharedLibraries = mInjector.getSharedLibrariesImpl();
        mBackgroundHandler = injector.getBackgroundHandler();

        mContext.getSystemService(DisplayManager.class)
                .getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics);
@@ -2900,9 +2931,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
            mPackageUsage.writeNow(mSettings.getPackagesLocked());

            if (mHandler.hasMessages(WRITE_SETTINGS)
                    || mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)
                    || mBackgroundHandler.hasMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS)
                    || mHandler.hasMessages(WRITE_PACKAGE_LIST)) {
                writeSettings();
                writeSettings(/*sync=*/true);
            }
        }
    }
@@ -3966,7 +3997,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
        synchronized (mDirtyUsers) {
            mDirtyUsers.remove(userId);
            if (mDirtyUsers.isEmpty()) {
                mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
                mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS);
            }
        }
    }
@@ -6865,9 +6896,14 @@ public class PackageManagerService implements PackageSender, TestUtilityService
     * TODO: In the meantime, can this be moved to a schedule call?
     * TODO(b/182523293): This should be removed once we finish migration of permission storage.
     */
    void writeSettingsLPrTEMP() {
    void writeSettingsLPrTEMP(boolean sync) {
        mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions);
        mSettings.writeLPr(mLiveComputer);
        mSettings.writeLPr(mLiveComputer, sync);
    }

    // Default async version.
    void writeSettingsLPrTEMP() {
        writeSettingsLPrTEMP(/*sync=*/false);
    }

    @Override
+316 −209
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;

import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.pm.PackageManagerService.WRITE_USER_PACKAGE_RESTRICTIONS;
import static com.android.server.pm.SharedUidMigration.BEST_EFFORT;

import android.annotation.NonNull;
@@ -56,7 +57,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.CreateAppDataArgs;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Message;
@@ -375,6 +375,13 @@ public final class Settings implements Watchable, Snappable {
    /** The top level directory in configfs for sdcardfs to push the package->uid,userId mappings */
    private final File mKernelMappingFilename;

    // Lock for user package restrictions operations.
    private final Object mPackageRestrictionsLock = new Object();

    // Pending write operations.
    @GuardedBy("mPackageRestrictionsLock")
    private final SparseIntArray mPendingAsyncPackageRestrictionsWrites = new SparseIntArray();

    /** Map from package name to settings */
    @Watched
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@@ -1469,31 +1476,46 @@ public final class Settings implements Watchable, Snappable {
        return (userId == UserHandle.USER_ALL) ? null : mDefaultBrowserApp.removeReturnOld(userId);
    }

    private File getUserPackagesStateFile(int userId) {
        // TODO: Implement a cleaner solution when adding tests.
    private File getUserSystemDirectory(int userId) {
        // This instead of Environment.getUserSystemDirectory(userId) to support testing.
        File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
        return new File(userDir, "package-restrictions.xml");
        return new File(new File(mSystemDir, "users"), Integer.toString(userId));
    }

    private File getUserRuntimePermissionsFile(int userId) {
        // TODO: Implement a cleaner solution when adding tests.
        // This instead of Environment.getUserSystemDirectory(userId) to support testing.
        File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
        return new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME);
    // The method itself does not have to be guarded, but the file does.
    @GuardedBy("mPackageRestrictionsLock")
    private File getUserPackagesStateFile(int userId) {
        return new File(getUserSystemDirectory(userId), "package-restrictions.xml");
    }

    // The method itself does not have to be guarded, but the file does.
    @GuardedBy("mPackageRestrictionsLock")
    private File getUserPackagesStateBackupFile(int userId) {
        return new File(Environment.getUserSystemDirectory(userId),
                "package-restrictions-backup.xml");
        return new File(getUserSystemDirectory(userId), "package-restrictions-backup.xml");
    }

    private File getUserRuntimePermissionsFile(int userId) {
        return new File(getUserSystemDirectory(userId), RUNTIME_PERMISSIONS_FILE_NAME);
    }

    // Default version is writing restrictions asynchronously.
    void writeAllUsersPackageRestrictionsLPr() {
        writeAllUsersPackageRestrictionsLPr(/*sync=*/false);
    }

    void writeAllUsersPackageRestrictionsLPr(boolean sync) {
        List<UserInfo> users = getAllUsers(UserManagerService.getInstance());
        if (users == null) return;

        if (sync) {
            // Cancel all pending per-user writes.
            synchronized (mPackageRestrictionsLock) {
                mPendingAsyncPackageRestrictionsWrites.clear();
            }
            mHandler.removeMessages(WRITE_USER_PACKAGE_RESTRICTIONS);
        }

        for (UserInfo user : users) {
            writePackageRestrictionsLPr(user.id);
            writePackageRestrictionsLPr(user.id, sync);
        }
    }

@@ -1684,6 +1706,8 @@ public final class Settings implements Watchable, Snappable {
            Log.i(TAG, "Reading package restrictions for user=" + userId);
        }
        FileInputStream str = null;

        synchronized (mPackageRestrictionsLock) {
            File userPackagesStateFile = getUserPackagesStateFile(userId);
            File backupFile = getUserPackagesStateBackupFile(userId);
            if (backupFile.exists()) {
@@ -1705,9 +1729,20 @@ public final class Settings implements Watchable, Snappable {
                }
            }

            if (str == null && userPackagesStateFile.exists()) {
                try {
                    str = new FileInputStream(userPackagesStateFile);
                    if (DEBUG_MU) Log.i(TAG, "Reading " + userPackagesStateFile);
                } catch (java.io.IOException e) {
                    mReadMessages.append("Error reading: " + e.toString());
                    PackageManagerService.reportSettingsProblem(Log.ERROR,
                            "Error reading settings: " + e);
                    Slog.wtf(TAG, "Error reading package manager stopped packages", e);
                }
            }
        }

        if (str == null) {
                if (!userPackagesStateFile.exists()) {
            mReadMessages.append("No stopped packages file found\n");
            PackageManagerService.reportSettingsProblem(Log.INFO,
                    "No stopped packages file; "
@@ -1738,9 +1773,8 @@ public final class Settings implements Watchable, Snappable {
            }
            return;
        }
                str = new FileInputStream(userPackagesStateFile);
                if (DEBUG_MU) Log.i(TAG, "Reading " + userPackagesStateFile);
            }

        try {
            final TypedXmlPullParser parser = Xml.resolvePullParser(str);

            int type;
@@ -2063,18 +2097,62 @@ public final class Settings implements Watchable, Snappable {
        }
    }

    // Default version is writing restrictions asynchronously.
    void writePackageRestrictionsLPr(int userId) {
        writePackageRestrictionsLPr(userId, /*sync=*/false);
    }

    void writePackageRestrictionsLPr(int userId, boolean sync) {
        invalidatePackageCache();

        final long startTime = SystemClock.uptimeMillis();

        if (sync) {
            writePackageRestrictions(userId, startTime, sync);
        } else {
            if (DEBUG_MU) {
            Log.i(TAG, "Writing package restrictions for user=" + userId);
                Log.i(TAG, "Scheduling deferred IO sync for user=" + userId);
            }
            synchronized (mPackageRestrictionsLock) {
                int pending = mPendingAsyncPackageRestrictionsWrites.get(userId, 0) + 1;
                mPendingAsyncPackageRestrictionsWrites.put(userId, pending);
            }
            Runnable r = () -> writePackageRestrictions(userId, startTime, sync);
            mHandler.obtainMessage(WRITE_USER_PACKAGE_RESTRICTIONS, r).sendToTarget();
        }
    }

    void writePackageRestrictions(Integer[] userIds) {
        invalidatePackageCache();
        final long startTime = SystemClock.uptimeMillis();
        for (int userId : userIds) {
            writePackageRestrictions(userId, startTime, /*sync=*/true);
        }
    }

    void writePackageRestrictions(int userId, long startTime, boolean sync) {
        if (DEBUG_MU) {
            Log.i(TAG, "Writing package restrictions for user=" + userId);
        }

        final File userPackagesStateFile;
        final File backupFile;
        final FileOutputStream fstr;

        synchronized (mPackageRestrictionsLock) {
            if (!sync) {
                int pending = mPendingAsyncPackageRestrictionsWrites.get(userId, 0) - 1;
                if (pending < 0) {
                    Log.i(TAG, "Cancel writing package restrictions for user=" + userId);
                    return;
                }
                mPendingAsyncPackageRestrictionsWrites.put(userId, pending);
            }

            // Keep the old stopped packages around until we know the new ones have
            // been successfully written.
        File userPackagesStateFile = getUserPackagesStateFile(userId);
        File backupFile = getUserPackagesStateBackupFile(userId);
            userPackagesStateFile = getUserPackagesStateFile(userId);
            backupFile = getUserPackagesStateBackupFile(userId);
            new File(userPackagesStateFile.getParent()).mkdirs();
            if (userPackagesStateFile.exists()) {
                // Presence of backup settings file indicates that we failed
@@ -2095,10 +2173,26 @@ public final class Settings implements Watchable, Snappable {
            }

            try {
            final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile);
                fstr = new FileOutputStream(userPackagesStateFile);
                // File is created, set permissions.
                FileUtils.setPermissions(userPackagesStateFile.toString(),
                        FileUtils.S_IRUSR | FileUtils.S_IWUSR
                                | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                        -1, -1);
            } catch (java.io.IOException e) {
                Slog.wtf(PackageManagerService.TAG,
                        "Unable to write package manager user packages state, "
                                + " current changes will be lost at reboot", e);
                return;
            }
        }

        try {
            synchronized (mLock) {
                final TypedXmlSerializer serializer = Xml.resolveSerializer(fstr);
                serializer.startDocument(null, true);
            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
                serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
                        true);

                serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);

@@ -2217,18 +2311,26 @@ public final class Settings implements Watchable, Snappable {
                serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);

                serializer.endDocument();
            }

            fstr.flush();
            FileUtils.sync(fstr);
            fstr.close();
            IoUtils.closeQuietly(fstr);

            // New settings successfully written, old ones are no longer
            // needed.
            backupFile.delete();
            synchronized (mPackageRestrictionsLock) {
                // File is created, set permissions.
                FileUtils.setPermissions(userPackagesStateFile.toString(),
                        FileUtils.S_IRUSR | FileUtils.S_IWUSR
                                | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                        -1, -1);
                // New settings successfully written, old ones are no longer needed.
                backupFile.delete();
            }

            if (DEBUG_MU) {
                Log.i(TAG, "New settings successfully written for user=" + userId + ": "
                        + userPackagesStateFile);
            }

            com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
                    "package-user-" + userId, SystemClock.uptimeMillis() - startTime);
@@ -2446,7 +2548,7 @@ public final class Settings implements Watchable, Snappable {
        }
    }

    void writeLPr(@NonNull Computer computer) {
    void writeLPr(@NonNull Computer computer, boolean sync) {
        //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);

        final long startTime = SystemClock.uptimeMillis();
@@ -2569,7 +2671,7 @@ public final class Settings implements Watchable, Snappable {

            writeKernelMappingLPr();
            writePackageListLPr();
            writeAllUsersPackageRestrictionsLPr();
            writeAllUsersPackageRestrictionsLPr(sync);
            writeAllRuntimePermissionsLPr();
            com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
                    "package", SystemClock.uptimeMillis() - startTime);
@@ -3200,7 +3302,7 @@ public final class Settings implements Watchable, Snappable {
            mBackupStoppedPackagesFilename.delete();
            mStoppedPackagesFilename.delete();
            // Migrate to new file format
            writePackageRestrictionsLPr(UserHandle.USER_SYSTEM);
            writePackageRestrictionsLPr(UserHandle.USER_SYSTEM, /*sync=*/true);
        } else {
            for (UserInfo user : users) {
                readPackageRestrictionsLPr(user.id, originalFirstInstallTimes);
@@ -4271,10 +4373,15 @@ public final class Settings implements Watchable, Snappable {
            entry.getValue().removeUser(userId);
        }
        mPreferredActivities.remove(userId);

        synchronized (mPackageRestrictionsLock) {
            File file = getUserPackagesStateFile(userId);
            file.delete();
            file = getUserPackagesStateBackupFile(userId);
            file.delete();
            mPendingAsyncPackageRestrictionsWrites.delete(userId);
        }

        removeCrossProfileIntentFiltersLPw(userId);

        mRuntimePermissionsPersistence.onUserRemoved(userId);
@@ -4319,7 +4426,7 @@ public final class Settings implements Watchable, Snappable {
        if (mVerifierDeviceIdentity == null) {
            mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();

            writeLPr(computer);
            writeLPr(computer, /*sync=*/false);
        }

        return mVerifierDeviceIdentity;
+221 −25

File changed.

Preview size limit exceeded, changes collapsed.