mt6735: Add PersistentStorage and UniqueDeviceId.

Adds cmhw implementations for the unique device id interface using the
EMMC id and persist storage in /persist_s.

Change-Id: Ic2dba55586453b31f31844b344ad43480472e13a
This commit is contained in:
Diogo Ferreira 2016-04-07 16:51:42 +01:00 committed by Mister Oyster
parent 303581aac3
commit 39034433b2
5 changed files with 268 additions and 0 deletions

View File

@ -0,0 +1,196 @@
/*
* 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.hardware;
import android.os.FileUtils;
import android.util.Slog;
import java.io.File;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Support for storage of key-value pairs which persists across device wipes /
* factory resets. This is used for various security related features. A
* reasonable implementation of this needs to store items on a partition which
* is unaffected by factory reset. The actual format of the storage is left up
* to the implementation. The implementation in this file is suitable for
* devices which have a /persist partition (recent QCOM devices fit this
* criteria).
*/
public class PersistentStorage {
public static final int MAX_KEY_LEN = 64;
public static final int MAX_VALUE_LEN = 4096;
private static final String TAG = "PersistentStorage";
private static final String PERSIST_DATA_PATH = "/protect_s/properties";
private static final boolean DEBUG = false;
private static final ReadWriteLock rwl = new ReentrantReadWriteLock();
/**
* Whether device supports persistent properties
*
* @return boolean Supported devices must return always true
*/
public static boolean isSupported() {
final File file = new File(PERSIST_DATA_PATH);
return file.exists() && file.isDirectory() && file.canRead() && file.canWrite();
}
/**
* Gets an array of bytes from persistent storage.
*
* @param key
* @return previously stored byte array, null if not found
*/
public static byte[] get(String key) {
if (!isSupported() || key.length() > MAX_KEY_LEN) {
return null;
}
final String encodedKey = encode(key);
if (encodedKey == null) {
return null;
}
FileInputStream fis = null;
try {
rwl.readLock().lock();
final File prop = new File(PERSIST_DATA_PATH + "/" + encodedKey);
if (!prop.exists()) {
if (DEBUG) {
Slog.e(TAG, "Unable to read from " + prop.getAbsolutePath());
}
return null;
}
final byte[] buffer = new byte[MAX_VALUE_LEN];
fis = new FileInputStream(prop);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = fis.read(buffer);
bos.write(buffer, 0, len);
return bos.toByteArray();
} catch (Exception e) {
Slog.e(TAG, e.getMessage(), e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException ex) {
// skip it
}
}
rwl.readLock().unlock();
}
return null;
}
/**
* Writes a byte array to persistent storage.
*
* The storage of the data is implementation specific. In this implementation,
* we hash the key with SHA-256 and use the hex string as the stored key.
*
* Implementations should delete the key if a null buffer is passed.
*
* @param key
* @param buffer
* @return true if the operation succeeded
*/
public static boolean set(String key, byte[] buffer) {
if (!isSupported() ||
key == null || key.length() > MAX_KEY_LEN ||
(buffer != null && buffer.length > MAX_VALUE_LEN)) {
return false;
}
final String encodedKey = encode(key);
if (encodedKey == null) {
return false;
}
try {
rwl.writeLock().lock();
final File prop = new File(PERSIST_DATA_PATH + "/" + encodedKey);
File tmp = null;
if (buffer != null) {
tmp = File.createTempFile(key, "tmp",
new File(PERSIST_DATA_PATH));
if (!FileUtils.copyToFile(new ByteArrayInputStream(buffer), tmp)) {
Slog.e(TAG, "Unable to create temporary file!");
return false;
}
}
if (prop.exists()) {
prop.delete();
}
if (tmp != null) {
tmp.renameTo(prop);
}
} catch (Exception e) {
Slog.e(TAG, e.getMessage(), e);
return false;
} finally {
rwl.writeLock().unlock();
}
return true;
}
/**
* Used for encoding keys with SHA-256
*
* @param key
* @return
*/
private static String encode(String key) {
try {
MessageDigest d = MessageDigest.getInstance("SHA-256");
byte[] hash = d.digest(key.getBytes("UTF-8"));
StringBuilder encoded = new StringBuilder();
for (byte b : hash) {
encoded.append(String.format("%02x", b & 0xff));
}
return encoded.toString();
} catch (Exception e) {
Slog.e(TAG, e.getMessage(), e);
}
return null;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2016 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.hardware;
import org.cyanogenmod.hardware.util.FileUtils;
/**
* Generate a unique but deterministic ID for this hardware, based on unchangeable
* hardware serial numbers.
*/
public class UniqueDeviceId {
private static final int TYPE_MMC0_CID = 0;
private static String sUniqueId = null;
/**
* Whether device supports reporting a unique device id.
*
* @return boolean Supported devices must return always true
*/
public static boolean isSupported() {
return getUniqueDeviceIdInternal() != null;
}
/**
* This method retreives a unique ID for the device.
*
* @return String The unique device ID
*/
public static String getUniqueDeviceId() {
return getUniqueDeviceIdInternal();
}
private static String getUniqueDeviceIdInternal() {
if (sUniqueId != null) {
return sUniqueId;
}
String sMmcType = FileUtils.readOneLine("/sys/block/mmcblk0/device/type");
String sCid = FileUtils.readOneLine("/sys/block/mmcblk0/device/cid");
if ("MMC".equals(sMmcType) && sCid != null) {
sCid = sCid.trim();
if (sCid.length() == 32) {
sUniqueId = String.format("%03x00000%32s", TYPE_MMC0_CID, sCid);
return sUniqueId;
}
}
/* Any additional types should be added here. */
return null;
}
}

View File

@ -97,6 +97,8 @@ on post-fs
chown system system /protect_s
chmod 0770 /protect_s
mkdir /protect_s/properties 0770 system system
mkdir /nvdata/APCFG 0770 system camera
mkdir /nvdata/APCFG/APRDCL 0770 system camera
mkdir /nvdata/APCFG/APRDEB 0770 system camera

View File

@ -234,6 +234,7 @@
/dev/shf u:object_r:shf_device:s0
/protect_f(/.*)? u:object_r:protect_f_data_file:s0
/protect_s(/.*)? u:object_r:protect_s_data_file:s0
/protect_s/properties(/.*)? u:object_r:persist_property_file:s0
/persist(/.*)? u:object_r:persist_data_file:s0
/dev/ttyACM0 u:object_r:ttyACM_device:s0
/dev/hrm u:object_r:hrm_device:s0

View File

@ -154,6 +154,8 @@ allow system_server zygote:unix_stream_socket { getopt getattr };
# Purpose : for kill-switch should only grant to access frp partition, to be fix
allow system_server platformblk_device:dir search;
# Persist
allow system_server protect_s_data_file:dir r_dir_perms;
# Debugfs
allow system_server debugfs:dir { read open };