cmsdk: Add persistent properties API

* Add support for reading and writing values from/to persistent
   storage. Requires the MANAGE_PERSISTENT_STORAGE permission, which
   should not be available for general use by applications.

Change-Id: I8a793396d207f23fcda851c172372f2073778eec
This commit is contained in:
Steve Kondik
2015-08-31 18:43:51 -07:00
committed by Gerrit Code Review
parent 087f2b536d
commit 7cef6f6945
8 changed files with 303 additions and 1 deletions

View File

@@ -38,6 +38,7 @@ import org.cyanogenmod.hardware.DisplayModeControl;
import org.cyanogenmod.hardware.HighTouchSensitivity;
import org.cyanogenmod.hardware.KeyDisabler;
import org.cyanogenmod.hardware.LongTermOrbits;
import org.cyanogenmod.hardware.PersistentStorage;
import org.cyanogenmod.hardware.SerialNumber;
import org.cyanogenmod.hardware.SunlightEnhancement;
import org.cyanogenmod.hardware.TapToWake;
@@ -79,6 +80,9 @@ public class CMHardwareService extends SystemService {
public DisplayMode getCurrentDisplayMode();
public DisplayMode getDefaultDisplayMode();
public boolean setDisplayMode(DisplayMode mode, boolean makeDefault);
public boolean writePersistentBytes(String key, byte[] value);
public byte[] readPersistentBytes(String key);
}
private class LegacyCMHardware implements CMHardwareInterface {
@@ -114,6 +118,8 @@ public class CMHardwareService extends SystemService {
mSupportedFeatures |= CMHardwareManager.FEATURE_AUTO_CONTRAST;
if (DisplayModeControl.isSupported())
mSupportedFeatures |= CMHardwareManager.FEATURE_DISPLAY_MODES;
if (PersistentStorage.isSupported())
mSupportedFeatures |= CMHardwareManager.FEATURE_PERSISTENT_STORAGE;
}
public int getSupportedFeatures() {
@@ -293,6 +299,14 @@ public class CMHardwareService extends SystemService {
public boolean setDisplayMode(DisplayMode mode, boolean makeDefault) {
return DisplayModeControl.setMode(mode, makeDefault);
}
public boolean writePersistentBytes(String key, byte[] value) {
return PersistentStorage.set(key, value);
}
public byte[] readPersistentBytes(String key) {
return PersistentStorage.get(key);
}
}
private CMHardwareInterface getImpl(Context context) {
@@ -524,5 +538,27 @@ public class CMHardwareService extends SystemService {
}
return mCmHwImpl.setDisplayMode(mode, makeDefault);
}
@Override
public boolean writePersistentBytes(String key, byte[] value) {
mContext.enforceCallingOrSelfPermission(
cyanogenmod.platform.Manifest.permission.MANAGE_PERSISTENT_STORAGE, null);
if (!isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE)) {
Log.e(TAG, "Persistent storage is not supported");
return false;
}
return mCmHwImpl.writePersistentBytes(key, value);
}
@Override
public byte[] readPersistentBytes(String key) {
mContext.enforceCallingOrSelfPermission(
cyanogenmod.platform.Manifest.permission.MANAGE_PERSISTENT_STORAGE, null);
if (!isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE)) {
Log.e(TAG, "Persistent storage is not supported");
return null;
}
return mCmHwImpl.readPersistentBytes(key);
}
};
}

View File

@@ -113,6 +113,13 @@
android:label="@string/permlab_read_alarms"
android:description="@string/permdesc_read_alarms"/>
<!-- Allows an application to access persistent property storage
<p>Not for use by third-party applications. -->
<permission android:name="cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE"
android:label="@string/permlab_managePersistentStorage"
android:description="@string/permdesc_managePersistentStorage"
android:protectionLevel="system|signature" />
<application android:process="system"
android:persistent="true"
android:hasCode="false"

View File

@@ -66,6 +66,10 @@
<string name="permlab_writeSecureSettings">modify CM secure system settings</string>
<string name="permdesc_writeSecureSettings">Allows an app to modify CM secure system settings. Not for use by normal apps.</string>
<!-- Labels for the MANAGE_PERSISTENT_STORAGE permission. -->
<string name="permlab_managePersistentStorage">manage persistent storage</string>
<string name="permdesc_managePersistentStorage">Allows an app to read or write properties which may persist thru a factory reset.</string>
<!-- Label to show for a service that is running because it is observing the user's custom tiles. -->
<string name="custom_tile_listener_binding_label">Custom tile listener</string>

View File

@@ -23,7 +23,9 @@ import android.util.Log;
import cyanogenmod.app.CMContextConstants;
import java.io.UnsupportedEncodingException;
import java.lang.IllegalArgumentException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
@@ -112,6 +114,11 @@ public final class CMHardwareManager {
*/
public static final int FEATURE_DISPLAY_MODES = 0x2000;
/**
* Persistent storage
*/
public static final int FEATURE_PERSISTENT_STORAGE = 0x4000;
private static final List<Integer> BOOLEAN_FEATURES = Arrays.asList(
FEATURE_ADAPTIVE_BACKLIGHT,
FEATURE_COLOR_ENHANCEMENT,
@@ -412,6 +419,132 @@ public final class CMHardwareManager {
return false;
}
/**
* Write a string to persistent storage, which persists thru factory reset
*
* @param key String identifier for this item
* @param value The UTF-8 encoded string to store
* @return true on success
*/
public boolean writePersistentString(String key, String value) {
try {
if (checkService()) {
return getService().writePersistentBytes(key,
value == null ? null : value.getBytes("UTF-8"));
}
} catch (RemoteException e) {
} catch (UnsupportedEncodingException e) {
Log.e(TAG, e.getMessage(), e);
}
return false;
}
/**
* Write an integer to persistent storage, which persists thru factory reset
*
* @param key String identifier for this item
* @param value The integer to store
* @return true on success
*/
public boolean writePersistentInt(String key, int value) {
try {
if (checkService()) {
return getService().writePersistentBytes(key,
ByteBuffer.allocate(4).putInt(value).array());
}
} catch (RemoteException e) {
}
return false;
}
/**
* Write a byte array to persistent storage, which persists thru factory reset
*
* @param key String identifier for this item
* @param value The byte array to store, up to 4096 bytes
* @return true on success
*/
public boolean writePersistentBytes(String key, byte[] value) {
try {
if (checkService()) {
return getService().writePersistentBytes(key, value);
}
} catch (RemoteException e) {
}
return false;
}
/**
* Read a string from persistent storage
*
* @param key String identifier for this item
* @return the stored UTF-8 encoded string, null if not found
*/
public String readPersistentString(String key) {
try {
if (checkService()) {
byte[] bytes = getService().readPersistentBytes(key);
if (bytes != null) {
return new String(bytes, "UTF-8");
}
}
} catch (RemoteException e) {
} catch (UnsupportedEncodingException e) {
Log.e(TAG, e.getMessage(), e);
}
return null;
}
/**
* Read an integer from persistent storage
*
* @param key String identifier for this item
* @return the stored integer, zero if not found
*/
public int readPersistentInt(String key) {
try {
if (checkService()) {
byte[] bytes = getService().readPersistentBytes(key);
if (bytes != null) {
return ByteBuffer.wrap(bytes).getInt();
}
}
} catch (RemoteException e) {
}
return 0;
}
/**
* Read a byte array from persistent storage
*
* @param key String identifier for this item
* @return the stored byte array, null if not found
*/
public byte[] readPersistentBytes(String key) {
try {
if (checkService()) {
return getService().readPersistentBytes(key);
}
} catch (RemoteException e) {
}
return null;
}
/** Delete an object from persistent storage
*
* @param key String identifier for this item
* @return true if an item was deleted
*/
public boolean deletePersistentObject(String key) {
try {
if (checkService()) {
return getService().writePersistentBytes(key, null);
}
} catch (RemoteException e) {
}
return false;
}
/**
* {@hide}
*/

View File

@@ -47,4 +47,7 @@ interface ICMHardwareService {
DisplayMode getCurrentDisplayMode();
DisplayMode getDefaultDisplayMode();
boolean setDisplayMode(in DisplayMode mode, boolean makeDefault);
boolean writePersistentBytes(String key, in byte[] bytes);
byte[] readPersistentBytes(String key);
}

View File

@@ -18,6 +18,7 @@
<uses-permission android:name="cyanogenmod.permission.READ_MSIM_PHONE_STATE" />
<uses-permission android:name="cyanogenmod.permission.HARDWARE_ABSTRACTION_ACCESS" />
<uses-permission android:name="cyanogenmod.permission.MODIFY_PROFILES" />
<uses-permission android:name="cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE" />
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<uses-library android:name="android.test.runner" />
@@ -70,6 +71,7 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".customtiles.DummySettings"
android:label="@string/app_name" />
</application>

View File

@@ -47,7 +47,8 @@ public class CMHardwareTest extends TestActivity {
CMHardwareManager.FEATURE_TAP_TO_WAKE,
CMHardwareManager.FEATURE_TOUCH_HOVERING,
CMHardwareManager.FEATURE_AUTO_CONTRAST,
CMHardwareManager.FEATURE_DISPLAY_MODES
CMHardwareManager.FEATURE_DISPLAY_MODES,
CMHardwareManager.FEATURE_PERSISTENT_STORAGE
);
private static final List<Integer> BOOLEAN_FEATURES = Arrays.asList(
@@ -127,6 +128,16 @@ public class CMHardwareTest extends TestActivity {
}
}
private boolean persistentStorageSupported() {
if (mHardwareManager.isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE)) {
return true;
} else {
Toast.makeText(CMHardwareTest.this, "Persistent storage not supported",
Toast.LENGTH_SHORT).show();
return false;
}
}
private Test[] mTests = new Test[] {
new Test("Test get supported features") {
public void run() {

View File

@@ -0,0 +1,106 @@
/**
* Copyright (c) 2015, The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cyanogenmod.tests.hardware.unit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import cyanogenmod.hardware.CMHardwareManager;
import java.util.Arrays;
import java.util.Random;
import java.util.UUID;
public class PersistentStorageTest extends AndroidTestCase {
private CMHardwareManager mHardwareManager;
@Override
protected void setUp() throws Exception {
super.setUp();
mHardwareManager = CMHardwareManager.getInstance(mContext);
}
@SmallTest
public boolean testPersistentString() {
assertTrue(mHardwareManager.isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE));
String testKey = UUID.randomUUID().toString();
String testString = "IM IN UR STORAGE";
// write + read
assertTrue(mHardwareManager.writePersistentString(testKey, testString));
assertEquals(testString, mHardwareManager.readPersistentString(testKey));
// rewrite + read
assertTrue(mHardwareManager.writePersistentString(testKey, testString + " AGAIN"));
assertEquals(testString + " AGAIN", mHardwareManager.readPersistentString(testKey));
// erase + read
assertTrue(mHardwareManager.deletePersistentObject(testKey));
assertNull(mHardwareManager.readPersistentString(testKey));
return true;
}
@SmallTest
public boolean testPersistentInteger() {
assertTrue(mHardwareManager.isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE));
String testKey = UUID.randomUUID().toString();
int testInt = 49152;
// write + read
assertTrue(mHardwareManager.writePersistentInt(testKey, testInt));
assertEquals(testInt, mHardwareManager.readPersistentInt(testKey));
// rewrite + read
assertTrue(mHardwareManager.writePersistentInt(testKey, testInt * 2));
assertEquals(testInt * 2, mHardwareManager.readPersistentInt(testKey));
// erase + read
assertTrue(mHardwareManager.deletePersistentObject(testKey));
assertEquals(0, mHardwareManager.readPersistentInt(testKey));
return true;
}
@SmallTest
public boolean testPersistentBytes() {
assertTrue(mHardwareManager.isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE));
String testKey = UUID.randomUUID().toString();
byte[] testArray = new byte[1024];
byte[] testArray2 = new byte[4096];
new Random().nextBytes(testArray);
new Random().nextBytes(testArray2);
// write + read
assertTrue(mHardwareManager.writePersistentBytes(testKey, testArray));
assertTrue(Arrays.equals(testArray, mHardwareManager.readPersistentBytes(testKey)));
// write + read
assertTrue(mHardwareManager.writePersistentBytes(testKey, testArray2));
assertTrue(Arrays.equals(testArray2, mHardwareManager.readPersistentBytes(testKey)));
// erase + read
assertTrue(mHardwareManager.deletePersistentObject(testKey));
assertNull(mHardwareManager.readPersistentBytes(testKey));
return true;
}
}