package com.android.providers.settings;
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.MemoryIntArray;
import android.util.Slog;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import java.io.IOException;
final class GenerationRegistry {
private static final String LOG_TAG = "GenerationRegistry";
private static final boolean DEBUG = false;
private final Object mLock;
@GuardedBy("mLock")
private final SparseIntArray mKeyToIndexMap = new SparseIntArray();
@GuardedBy("mLock")
private MemoryIntArray mBackingStore;
public GenerationRegistry(Object lock) {
mLock = lock;
}
public void incrementGeneration(int key) {
synchronized (mLock) {
MemoryIntArray backingStore = getBackingStoreLocked();
if (backingStore != null) {
try {
final int index = getKeyIndexLocked(key, mKeyToIndexMap, backingStore);
if (index >= 0) {
final int generation = backingStore.get(index) + 1;
backingStore.set(index, generation);
}
} catch (IOException e) {
Slog.e(LOG_TAG, "Error updating generation id", e);
destroyBackingStore();
}
}
}
}
public void addGenerationData(Bundle bundle, int key) {
synchronized (mLock) {
MemoryIntArray backingStore = getBackingStoreLocked();
try {
if (backingStore != null) {
final int index = getKeyIndexLocked(key, mKeyToIndexMap, backingStore);
if (index >= 0) {
bundle.putParcelable(Settings.CALL_METHOD_TRACK_GENERATION_KEY,
backingStore);
bundle.putInt(Settings.CALL_METHOD_GENERATION_INDEX_KEY, index);
bundle.putInt(Settings.CALL_METHOD_GENERATION_KEY,
backingStore.get(index));
if (DEBUG) {
Slog.i(LOG_TAG, "Exported index:" + index + " for key:"
+ SettingsProvider.keyToString(key));
}
}
}
} catch (IOException e) {
Slog.e(LOG_TAG, "Error adding generation data", e);
destroyBackingStore();
}
}
}
public void onUserRemoved(int userId) {
synchronized (mLock) {
MemoryIntArray backingStore = getBackingStoreLocked();
if (backingStore != null && mKeyToIndexMap.size() > 0) {
try {
final int secureKey = SettingsProvider.makeKey(
SettingsProvider.SETTINGS_TYPE_SECURE, userId);
resetSlotForKeyLocked(secureKey, mKeyToIndexMap, backingStore);
final int systemKey = SettingsProvider.makeKey(
SettingsProvider.SETTINGS_TYPE_SYSTEM, userId);
resetSlotForKeyLocked(systemKey, mKeyToIndexMap, backingStore);
} catch (IOException e) {
Slog.e(LOG_TAG, "Error cleaning up for user", e);
destroyBackingStore();
}
}
}
}
private MemoryIntArray getBackingStoreLocked() {
if (mBackingStore == null) {
final int size = 1 + 2 + 10 + 2 * UserManager.getMaxSupportedUsers();
try {
mBackingStore = new MemoryIntArray(size);
if (DEBUG) {
Slog.e(LOG_TAG, "Created backing store " + mBackingStore);
}
} catch (IOException e) {
Slog.e(LOG_TAG, "Error creating generation tracker", e);
}
}
return mBackingStore;
}
private void destroyBackingStore() {
if (mBackingStore != null) {
try {
mBackingStore.close();
if (DEBUG) {
Slog.e(LOG_TAG, "Destroyed backing store " + mBackingStore);
}
} catch (IOException e) {
Slog.e(LOG_TAG, "Cannot close generation memory array", e);
}
mBackingStore = null;
}
}
private static void resetSlotForKeyLocked(int key, SparseIntArray keyToIndexMap,
MemoryIntArray backingStore) throws IOException {
final int index = keyToIndexMap.get(key, -1);
if (index >= 0) {
keyToIndexMap.delete(key);
backingStore.set(index, 0);
if (DEBUG) {
Slog.i(LOG_TAG, "Freed index:" + index + " for key:"
+ SettingsProvider.keyToString(key));
}
}
}
private static int getKeyIndexLocked(int key, SparseIntArray keyToIndexMap,
MemoryIntArray backingStore) throws IOException {
int index = keyToIndexMap.get(key, -1);
if (index < 0) {
index = findNextEmptyIndex(backingStore);
if (index >= 0) {
backingStore.set(index, 1);
keyToIndexMap.append(key, index);
if (DEBUG) {
Slog.i(LOG_TAG, "Allocated index:" + index + " for key:"
+ SettingsProvider.keyToString(key));
}
} else {
Slog.e(LOG_TAG, "Could not allocate generation index");
}
}
return index;
}
private static int findNextEmptyIndex(MemoryIntArray backingStore) throws IOException {
final int size = backingStore.size();
for (int i = 0; i < size; i++) {
if (backingStore.get(i) == 0) {
return i;
}
}
return -1;
}
}