diff options
| -rw-r--r-- | core/java/android/appwidget/flags.aconfig | 9 | ||||
| -rw-r--r-- | services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java | 71 |
2 files changed, 75 insertions, 5 deletions
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig index c95b864c08bb..ec2e5fe23ab9 100644 --- a/core/java/android/appwidget/flags.aconfig +++ b/core/java/android/appwidget/flags.aconfig @@ -12,4 +12,11 @@ flag { namespace: "app_widgets" description: "Enable adapter conversion to RemoteCollectionItemsAdapter" bug: "245950570" -}
\ No newline at end of file +} + +flag { + name: "remove_app_widget_service_io_from_critical_path" + namespace: "app_widgets" + description: "Move state file IO to non-critical path" + bug: "312949280" +} diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index a4b28967e3b2..cab2d74c27d1 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -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); - mSaveStateHandler = BackgroundThread.getHandler(); + 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,7 +1985,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private void saveGroupStateAsync(int groupId) { - mSaveStateHandler.post(new SaveStateRunnable(groupId)); + if (removeAppWidgetServiceIoFromCriticalPath()) { + mSaveStateHandler.removeMessages(groupId); + mSaveStateHandler.sendEmptyMessage(groupId); + } else { + mSaveStateHandler.post(new SaveStateRunnable(groupId)); + } } private void updateAppWidgetInstanceLocked(Widget widget, RemoteViews views, @@ -3104,6 +3150,23 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @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 { |