Persist settings on a dedicated background thread
Settings were persisted on the system background thread but during first boot the device is under heavy load and persisting settings competes with other system components using the shared background thread. As a result persisting settings can be delayed much longer than the expected 200ms. This can cause issues with setup wizard being skipped/went over and its component disaabled being persisted but the setting whether the device is provisioned not being persisted - now if the device boots it will have no SUW but also the home button would be missing. Generally, we need a tansactional abstraction in the system process to peform all delayed operations atomically. bug:25472484 Change-Id: Icf38e72403b190a8fa9d0554b8dd83ce78da3bc8
This commit is contained in:
committed by
Svetoslav Ganov
parent
c26aabadc3
commit
82b8c92b97
@ -46,6 +46,7 @@ import android.os.Debug;
|
|||||||
import android.os.DropBoxManager;
|
import android.os.DropBoxManager;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
@ -199,6 +200,12 @@ public class SettingsProvider extends ContentProvider {
|
|||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private SettingsRegistry mSettingsRegistry;
|
private SettingsRegistry mSettingsRegistry;
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private HandlerThread mHandlerThread;
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private Handler mBackgroundHandler;
|
||||||
|
|
||||||
// We have to call in the user manager with no lock held,
|
// We have to call in the user manager with no lock held,
|
||||||
private volatile UserManager mUserManager;
|
private volatile UserManager mUserManager;
|
||||||
|
|
||||||
@ -245,6 +252,10 @@ public class SettingsProvider extends ContentProvider {
|
|||||||
mUserManager = UserManager.get(getContext());
|
mUserManager = UserManager.get(getContext());
|
||||||
mPackageManager = AppGlobals.getPackageManager();
|
mPackageManager = AppGlobals.getPackageManager();
|
||||||
mSettingsRegistry = new SettingsRegistry();
|
mSettingsRegistry = new SettingsRegistry();
|
||||||
|
mHandlerThread = new HandlerThread(LOG_TAG,
|
||||||
|
Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
mHandlerThread.start();
|
||||||
|
mBackgroundHandler = new Handler(mHandlerThread.getLooper());
|
||||||
}
|
}
|
||||||
registerBroadcastReceivers();
|
registerBroadcastReceivers();
|
||||||
startWatchingUserRestrictionChanges();
|
startWatchingUserRestrictionChanges();
|
||||||
@ -1669,7 +1680,7 @@ public class SettingsProvider extends ContentProvider {
|
|||||||
if (mSettingsStates.get(key) == null) {
|
if (mSettingsStates.get(key) == null) {
|
||||||
final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
|
final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
|
||||||
SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
|
SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
|
||||||
maxBytesPerPackage);
|
maxBytesPerPackage, mBackgroundHandler);
|
||||||
mSettingsStates.put(key, settingsState);
|
mSettingsStates.put(key, settingsState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ final class SettingsState {
|
|||||||
|
|
||||||
private final Object mLock;
|
private final Object mLock;
|
||||||
|
|
||||||
private final Handler mHandler = new MyHandler();
|
private final Handler mHandler;
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private final ArrayMap<String, Setting> mSettings = new ArrayMap<>();
|
private final ArrayMap<String, Setting> mSettings = new ArrayMap<>();
|
||||||
@ -134,13 +134,15 @@ final class SettingsState {
|
|||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private long mNextId;
|
private long mNextId;
|
||||||
|
|
||||||
public SettingsState(Object lock, File file, int key, int maxBytesPerAppPackage) {
|
public SettingsState(Object lock, File file, int key, int maxBytesPerAppPackage,
|
||||||
|
Handler handler) {
|
||||||
// It is important that we use the same lock as the settings provider
|
// It is important that we use the same lock as the settings provider
|
||||||
// to ensure multiple mutations on this state are atomicaly persisted
|
// to ensure multiple mutations on this state are atomicaly persisted
|
||||||
// as the async persistence should be blocked while we make changes.
|
// as the async persistence should be blocked while we make changes.
|
||||||
mLock = lock;
|
mLock = lock;
|
||||||
mStatePersistFile = file;
|
mStatePersistFile = file;
|
||||||
mKey = key;
|
mKey = key;
|
||||||
|
mHandler = handler;
|
||||||
if (maxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_LIMITED) {
|
if (maxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_LIMITED) {
|
||||||
mMaxBytesPerAppPackage = maxBytesPerAppPackage;
|
mMaxBytesPerAppPackage = maxBytesPerAppPackage;
|
||||||
mPackageToMemoryUsage = new ArrayMap<>();
|
mPackageToMemoryUsage = new ArrayMap<>();
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.providers.settings;
|
package com.android.providers.settings;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
import android.util.Xml;
|
import android.util.Xml;
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ public class SettingsStateTest extends AndroidTestCase {
|
|||||||
final Object lock = new Object();
|
final Object lock = new Object();
|
||||||
|
|
||||||
final SettingsState ssWriter = new SettingsState(lock, file, 1,
|
final SettingsState ssWriter = new SettingsState(lock, file, 1,
|
||||||
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED);
|
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, new Handler());
|
||||||
ssWriter.setVersionLocked(SettingsState.SETTINGS_VERSOIN_NEW_ENCODING);
|
ssWriter.setVersionLocked(SettingsState.SETTINGS_VERSOIN_NEW_ENCODING);
|
||||||
|
|
||||||
ssWriter.insertSettingLocked("k1", "\u0000", "package");
|
ssWriter.insertSettingLocked("k1", "\u0000", "package");
|
||||||
@ -138,7 +139,7 @@ public class SettingsStateTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final SettingsState ssReader = new SettingsState(lock, file, 1,
|
final SettingsState ssReader = new SettingsState(lock, file, 1,
|
||||||
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED);
|
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, new Handler());
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
assertEquals("\u0000", ssReader.getSettingLocked("k1").getValue());
|
assertEquals("\u0000", ssReader.getSettingLocked("k1").getValue());
|
||||||
assertEquals("abc", ssReader.getSettingLocked("k2").getValue());
|
assertEquals("abc", ssReader.getSettingLocked("k2").getValue());
|
||||||
@ -165,7 +166,7 @@ public class SettingsStateTest extends AndroidTestCase {
|
|||||||
os.close();
|
os.close();
|
||||||
|
|
||||||
final SettingsState ss = new SettingsState(lock, file, 1,
|
final SettingsState ss = new SettingsState(lock, file, 1,
|
||||||
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED);
|
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, new Handler());
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
SettingsState.Setting s;
|
SettingsState.Setting s;
|
||||||
s = ss.getSettingLocked("k0");
|
s = ss.getSettingLocked("k0");
|
||||||
|
Reference in New Issue
Block a user