Loading packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +48 −27 Original line number Diff line number Diff line Loading @@ -376,9 +376,11 @@ final class SettingsState { Setting newSetting = new Setting(name, oldSetting.getValue(), null, oldSetting.getPackageName(), oldSetting.getTag(), false, oldSetting.getId()); mSettings.put(name, newSetting); updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue, int newSize = getNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue, newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue()); checkNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize); mSettings.put(name, newSetting); updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize); scheduleWriteIfNeededLocked(); } } Loading Loading @@ -410,6 +412,12 @@ final class SettingsState { Setting oldState = mSettings.get(name); String oldValue = (oldState != null) ? oldState.value : null; String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null; String newDefaultValue = makeDefault ? value : oldDefaultValue; int newSize = getNewMemoryUsagePerPackageLocked(packageName, oldValue, value, oldDefaultValue, newDefaultValue); checkNewMemoryUsagePerPackageLocked(packageName, newSize); Setting newState; if (oldState != null) { Loading @@ -430,8 +438,7 @@ final class SettingsState { addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState); updateMemoryUsagePerPackageLocked(packageName, oldValue, value, oldDefaultValue, newState.getDefaultValue()); updateMemoryUsagePerPackageLocked(packageName, newSize); scheduleWriteIfNeededLocked(); Loading Loading @@ -552,13 +559,14 @@ final class SettingsState { } Setting oldState = mSettings.remove(name); int newSize = getNewMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, null, oldState.defaultValue, null); FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, /* value= */ "", /* newValue= */ "", oldState.value, /* tag */ "", false, getUserIdFromKey(mKey), FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED); updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, null, oldState.defaultValue, null); updateMemoryUsagePerPackageLocked(oldState.packageName, newSize); addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState); Loading @@ -579,16 +587,18 @@ final class SettingsState { Setting oldSetting = new Setting(setting); String oldValue = setting.getValue(); String oldDefaultValue = setting.getDefaultValue(); String newValue = oldDefaultValue; String newDefaultValue = oldDefaultValue; int newSize = getNewMemoryUsagePerPackageLocked(setting.packageName, oldValue, newValue, oldDefaultValue, newDefaultValue); checkNewMemoryUsagePerPackageLocked(setting.packageName, newSize); if (!setting.reset()) { return false; } String newValue = setting.getValue(); String newDefaultValue = setting.getDefaultValue(); updateMemoryUsagePerPackageLocked(setting.packageName, oldValue, newValue, oldDefaultValue, newDefaultValue); updateMemoryUsagePerPackageLocked(setting.packageName, newSize); addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting); Loading Loading @@ -696,38 +706,49 @@ final class SettingsState { } @GuardedBy("mLock") private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue, String newValue, String oldDefaultValue, String newDefaultValue) { if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) { return; private boolean isExemptFromMemoryUsageCap(String packageName) { return mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED || SYSTEM_PACKAGE_NAME.equals(packageName); } if (SYSTEM_PACKAGE_NAME.equals(packageName)) { @GuardedBy("mLock") private void checkNewMemoryUsagePerPackageLocked(String packageName, int newSize) throws IllegalStateException { if (isExemptFromMemoryUsageCap(packageName)) { return; } if (newSize > mMaxBytesPerAppPackage) { throw new IllegalStateException("You are adding too many system settings. " + "You should stop using system settings for app specific data" + " package: " + packageName); } } @GuardedBy("mLock") private int getNewMemoryUsagePerPackageLocked(String packageName, String oldValue, String newValue, String oldDefaultValue, String newDefaultValue) { if (isExemptFromMemoryUsageCap(packageName)) { return 0; } final Integer currentSize = mPackageToMemoryUsage.get(packageName); final int oldValueSize = (oldValue != null) ? oldValue.length() : 0; final int newValueSize = (newValue != null) ? newValue.length() : 0; final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0; final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0; final int deltaSize = newValueSize + newDefaultValueSize - oldValueSize - oldDefaultValueSize; Integer currentSize = mPackageToMemoryUsage.get(packageName); final int newSize = Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0); if (newSize > mMaxBytesPerAppPackage) { throw new IllegalStateException("You are adding too many system settings. " + "You should stop using system settings for app specific data" + " package: " + packageName); return Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0); } @GuardedBy("mLock") private void updateMemoryUsagePerPackageLocked(String packageName, int newSize) { if (isExemptFromMemoryUsageCap(packageName)) { return; } if (DEBUG) { Slog.i(LOG_TAG, "Settings for package: " + packageName + " size: " + newSize + " bytes."); } mPackageToMemoryUsage.put(packageName, newSize); } Loading packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java +37 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.test.AndroidTestCase; import android.util.TypedXmlSerializer; import android.util.Xml; import com.google.common.base.Strings; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; Loading Loading @@ -276,4 +278,39 @@ public class SettingsStateTest extends AndroidTestCase { settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING); return settingsState; } public void testInsertSetting_memoryUsage() { SettingsState settingsState = getSettingStateObject(); // No exception should be thrown when there is no cap settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, "p1"); settingsState.deleteSettingLocked(SETTING_NAME); settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1, SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); // System package doesn't have memory usage limit settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, SYSTEM_PACKAGE); settingsState.deleteSettingLocked(SETTING_NAME); // Should not throw if usage is under the cap settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 19999), null, false, "p1"); settingsState.deleteSettingLocked(SETTING_NAME); try { settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, "p1"); fail("Should throw because it exceeded per package memory usage"); } catch (IllegalStateException ex) { assertTrue(ex.getMessage().contains("p1")); } try { settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, "p1"); fail("Should throw because it exceeded per package memory usage"); } catch (IllegalStateException ex) { assertTrue(ex.getMessage().contains("p1")); } assertTrue(settingsState.getSettingLocked(SETTING_NAME).isNull()); } } Loading
packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +48 −27 Original line number Diff line number Diff line Loading @@ -376,9 +376,11 @@ final class SettingsState { Setting newSetting = new Setting(name, oldSetting.getValue(), null, oldSetting.getPackageName(), oldSetting.getTag(), false, oldSetting.getId()); mSettings.put(name, newSetting); updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue, int newSize = getNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue, newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue()); checkNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize); mSettings.put(name, newSetting); updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize); scheduleWriteIfNeededLocked(); } } Loading Loading @@ -410,6 +412,12 @@ final class SettingsState { Setting oldState = mSettings.get(name); String oldValue = (oldState != null) ? oldState.value : null; String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null; String newDefaultValue = makeDefault ? value : oldDefaultValue; int newSize = getNewMemoryUsagePerPackageLocked(packageName, oldValue, value, oldDefaultValue, newDefaultValue); checkNewMemoryUsagePerPackageLocked(packageName, newSize); Setting newState; if (oldState != null) { Loading @@ -430,8 +438,7 @@ final class SettingsState { addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState); updateMemoryUsagePerPackageLocked(packageName, oldValue, value, oldDefaultValue, newState.getDefaultValue()); updateMemoryUsagePerPackageLocked(packageName, newSize); scheduleWriteIfNeededLocked(); Loading Loading @@ -552,13 +559,14 @@ final class SettingsState { } Setting oldState = mSettings.remove(name); int newSize = getNewMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, null, oldState.defaultValue, null); FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, /* value= */ "", /* newValue= */ "", oldState.value, /* tag */ "", false, getUserIdFromKey(mKey), FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED); updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, null, oldState.defaultValue, null); updateMemoryUsagePerPackageLocked(oldState.packageName, newSize); addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState); Loading @@ -579,16 +587,18 @@ final class SettingsState { Setting oldSetting = new Setting(setting); String oldValue = setting.getValue(); String oldDefaultValue = setting.getDefaultValue(); String newValue = oldDefaultValue; String newDefaultValue = oldDefaultValue; int newSize = getNewMemoryUsagePerPackageLocked(setting.packageName, oldValue, newValue, oldDefaultValue, newDefaultValue); checkNewMemoryUsagePerPackageLocked(setting.packageName, newSize); if (!setting.reset()) { return false; } String newValue = setting.getValue(); String newDefaultValue = setting.getDefaultValue(); updateMemoryUsagePerPackageLocked(setting.packageName, oldValue, newValue, oldDefaultValue, newDefaultValue); updateMemoryUsagePerPackageLocked(setting.packageName, newSize); addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting); Loading Loading @@ -696,38 +706,49 @@ final class SettingsState { } @GuardedBy("mLock") private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue, String newValue, String oldDefaultValue, String newDefaultValue) { if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) { return; private boolean isExemptFromMemoryUsageCap(String packageName) { return mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED || SYSTEM_PACKAGE_NAME.equals(packageName); } if (SYSTEM_PACKAGE_NAME.equals(packageName)) { @GuardedBy("mLock") private void checkNewMemoryUsagePerPackageLocked(String packageName, int newSize) throws IllegalStateException { if (isExemptFromMemoryUsageCap(packageName)) { return; } if (newSize > mMaxBytesPerAppPackage) { throw new IllegalStateException("You are adding too many system settings. " + "You should stop using system settings for app specific data" + " package: " + packageName); } } @GuardedBy("mLock") private int getNewMemoryUsagePerPackageLocked(String packageName, String oldValue, String newValue, String oldDefaultValue, String newDefaultValue) { if (isExemptFromMemoryUsageCap(packageName)) { return 0; } final Integer currentSize = mPackageToMemoryUsage.get(packageName); final int oldValueSize = (oldValue != null) ? oldValue.length() : 0; final int newValueSize = (newValue != null) ? newValue.length() : 0; final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0; final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0; final int deltaSize = newValueSize + newDefaultValueSize - oldValueSize - oldDefaultValueSize; Integer currentSize = mPackageToMemoryUsage.get(packageName); final int newSize = Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0); if (newSize > mMaxBytesPerAppPackage) { throw new IllegalStateException("You are adding too many system settings. " + "You should stop using system settings for app specific data" + " package: " + packageName); return Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0); } @GuardedBy("mLock") private void updateMemoryUsagePerPackageLocked(String packageName, int newSize) { if (isExemptFromMemoryUsageCap(packageName)) { return; } if (DEBUG) { Slog.i(LOG_TAG, "Settings for package: " + packageName + " size: " + newSize + " bytes."); } mPackageToMemoryUsage.put(packageName, newSize); } Loading
packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java +37 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.test.AndroidTestCase; import android.util.TypedXmlSerializer; import android.util.Xml; import com.google.common.base.Strings; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; Loading Loading @@ -276,4 +278,39 @@ public class SettingsStateTest extends AndroidTestCase { settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING); return settingsState; } public void testInsertSetting_memoryUsage() { SettingsState settingsState = getSettingStateObject(); // No exception should be thrown when there is no cap settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, "p1"); settingsState.deleteSettingLocked(SETTING_NAME); settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1, SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); // System package doesn't have memory usage limit settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, SYSTEM_PACKAGE); settingsState.deleteSettingLocked(SETTING_NAME); // Should not throw if usage is under the cap settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 19999), null, false, "p1"); settingsState.deleteSettingLocked(SETTING_NAME); try { settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, "p1"); fail("Should throw because it exceeded per package memory usage"); } catch (IllegalStateException ex) { assertTrue(ex.getMessage().contains("p1")); } try { settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, "p1"); fail("Should throw because it exceeded per package memory usage"); } catch (IllegalStateException ex) { assertTrue(ex.getMessage().contains("p1")); } assertTrue(settingsState.getSettingLocked(SETTING_NAME).isNull()); } }