Loading core/java/android/appwidget/flags.aconfig +8 −1 Original line number Diff line number Diff line Loading @@ -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" } services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +67 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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. Loading Loading @@ -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) { Loading Loading @@ -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(); Loading @@ -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); Loading Loading @@ -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 { Loading Loading
core/java/android/appwidget/flags.aconfig +8 −1 Original line number Diff line number Diff line Loading @@ -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" }
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +67 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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. Loading Loading @@ -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) { Loading Loading @@ -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(); Loading @@ -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); Loading Loading @@ -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 { Loading