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

Commit 442fbea9 authored by Sihua Ma's avatar Sihua Ma Committed by Android (Google) Code Review
Browse files

Merge "Move widget save state I/O job out of critical paths" into main

parents 1710a261 3a783878
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -13,3 +13,10 @@ flag {
  description: "Enable adapter conversion to RemoteCollectionItemsAdapter"
  bug: "245950570"
}

flag {
  name: "remove_app_widget_service_io_from_critical_path"
  namespace: "app_widgets"
  description: "Move state file IO to non-critical path"
  bug: "312949280"
}
+67 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.appwidget;

import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -144,6 +145,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -277,7 +279,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        mKeyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
        mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
        if (removeAppWidgetServiceIoFromCriticalPath()) {
            mSaveStateHandler = new Handler(BackgroundThread.get().getLooper(),
                    this::handleSaveMessage);
        } else {
            mSaveStateHandler = BackgroundThread.getHandler();
        }
        final ServiceThread serviceThread = new ServiceThread(TAG,
                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /* allowIo */);
        serviceThread.start();
@@ -314,6 +321,40 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        mMaxWidgetBitmapMemory = 6 * size.x * size.y;
    }

    private boolean handleSaveMessage(Message msg) {
        final int userId = msg.what;
        SparseArray<byte[]> userIdToBytesMapping;
        synchronized (mLock) {
            // No need to enforce unlocked state when there is no caller. User can be in the
            // stopping state or removed by the time the message is processed
            ensureGroupStateLoadedLocked(userId, false /* enforceUserUnlockingOrUnlocked */);
            userIdToBytesMapping = saveStateToByteArrayLocked(userId);
        }

        for (int i = 0; i < userIdToBytesMapping.size(); i++) {
            int currentProfileId = userIdToBytesMapping.keyAt(i);
            byte[] currentStateByteArray = userIdToBytesMapping.valueAt(i);
            AtomicFile currentFile = getSavedStateFile(currentProfileId);
            FileOutputStream fileStream;
            try {
                fileStream = currentFile.startWrite();
            } catch (IOException e) {
                Log.e(TAG, "Failed to start writing stream", e);
                continue;
            }

            try {
                fileStream.write(currentStateByteArray);
                currentFile.finishWrite(fileStream);
            } catch (IOException e) {
                Log.e(TAG, "Failed to write state byte stream to file", e);
                currentFile.failWrite(fileStream);
            }
        }

        return true;
    }

    private void registerBroadcastReceiver() {
        // Register for broadcasts about package install, etc., so we can
        // update the provider list.
@@ -1944,8 +1985,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
    }

    private void saveGroupStateAsync(int groupId) {
        if (removeAppWidgetServiceIoFromCriticalPath()) {
            mSaveStateHandler.removeMessages(groupId);
            mSaveStateHandler.sendEmptyMessage(groupId);
        } else {
            mSaveStateHandler.post(new SaveStateRunnable(groupId));
        }
    }

    private void updateAppWidgetInstanceLocked(Widget widget, RemoteViews views,
            boolean isPartialUpdate) {
@@ -3103,6 +3149,23 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        return false;
    }

    @GuardedBy("mLock")
    private @NonNull SparseArray<byte[]> saveStateToByteArrayLocked(int userId) {
        tagProvidersAndHosts();

        final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
        SparseArray<byte[]> userIdToBytesMapping = new SparseArray<>();

        for (int profileId : profileIds) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            if (writeProfileStateToStreamLocked(outputStream, profileId)) {
                userIdToBytesMapping.put(profileId, outputStream.toByteArray());
            }
        }

        return userIdToBytesMapping;
    }

    @GuardedBy("mLock")
    private void saveStateLocked(int userId) {
        tagProvidersAndHosts();
@@ -3117,7 +3180,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
            FileOutputStream stream;
            try {
                stream = file.startWrite();
                if (writeProfileStateToFileLocked(stream, profileId)) {
                if (writeProfileStateToStreamLocked(stream, profileId)) {
                    file.finishWrite(stream);
                } else {
                    file.failWrite(stream);
@@ -3158,7 +3221,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
    }

    @GuardedBy("mLock")
    private boolean writeProfileStateToFileLocked(FileOutputStream stream, int userId) {
    private boolean writeProfileStateToStreamLocked(OutputStream stream, int userId) {
        int N;

        try {