Service for reading and writing blocks to PST partition
Permits apps with permission android.permission.ACCESS_PERSISTENT_PARTITION to obtain a read and write data blocks to the PST partition. Only one block ever exists at one time in PST. When a client writes another block, the previous one is overwritten. This permits storing a block of data that will live across factory resets. Change-Id: I8f23df3531f3c0512118eb4b7530eff8a8e81c83
This commit is contained in:
@@ -210,6 +210,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/service/dreams/IDozeHardware.aidl \
|
||||
core/java/android/service/dreams/IDreamManager.aidl \
|
||||
core/java/android/service/dreams/IDreamService.aidl \
|
||||
core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \
|
||||
core/java/android/service/fingerprint/IFingerprintService.aidl \
|
||||
core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl \
|
||||
core/java/android/service/trust/ITrustAgentService.aidl \
|
||||
|
||||
@@ -47723,7 +47723,6 @@ package java.util {
|
||||
ctor public Locale(java.lang.String, java.lang.String);
|
||||
ctor public Locale(java.lang.String, java.lang.String, java.lang.String);
|
||||
method public java.lang.Object clone();
|
||||
method public static java.util.Locale forLanguageTag(java.lang.String);
|
||||
method public static java.util.Locale[] getAvailableLocales();
|
||||
method public java.lang.String getCountry();
|
||||
method public static java.util.Locale getDefault();
|
||||
@@ -47733,24 +47732,15 @@ package java.util {
|
||||
method public java.lang.String getDisplayLanguage(java.util.Locale);
|
||||
method public final java.lang.String getDisplayName();
|
||||
method public java.lang.String getDisplayName(java.util.Locale);
|
||||
method public java.lang.String getDisplayScript();
|
||||
method public java.lang.String getDisplayScript(java.util.Locale);
|
||||
method public final java.lang.String getDisplayVariant();
|
||||
method public java.lang.String getDisplayVariant(java.util.Locale);
|
||||
method public java.lang.String getExtension(char);
|
||||
method public java.util.Set<java.lang.Character> getExtensionKeys();
|
||||
method public java.lang.String getISO3Country();
|
||||
method public java.lang.String getISO3Language();
|
||||
method public static java.lang.String[] getISOCountries();
|
||||
method public static java.lang.String[] getISOLanguages();
|
||||
method public java.lang.String getLanguage();
|
||||
method public java.lang.String getScript();
|
||||
method public java.util.Set<java.lang.String> getUnicodeLocaleAttributes();
|
||||
method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
|
||||
method public java.lang.String getUnicodeLocaleType(java.lang.String);
|
||||
method public java.lang.String getVariant();
|
||||
method public static synchronized void setDefault(java.util.Locale);
|
||||
method public java.lang.String toLanguageTag();
|
||||
method public final java.lang.String toString();
|
||||
field public static final java.util.Locale CANADA;
|
||||
field public static final java.util.Locale CANADA_FRENCH;
|
||||
@@ -47768,33 +47758,14 @@ package java.util {
|
||||
field public static final java.util.Locale KOREA;
|
||||
field public static final java.util.Locale KOREAN;
|
||||
field public static final java.util.Locale PRC;
|
||||
field public static final char PRIVATE_USE_EXTENSION = 120; // 0x0078 'x'
|
||||
field public static final java.util.Locale ROOT;
|
||||
field public static final java.util.Locale SIMPLIFIED_CHINESE;
|
||||
field public static final java.util.Locale TAIWAN;
|
||||
field public static final java.util.Locale TRADITIONAL_CHINESE;
|
||||
field public static final java.util.Locale UK;
|
||||
field public static final char UNICODE_LOCALE_EXTENSION = 117; // 0x0075 'u'
|
||||
field public static final java.util.Locale US;
|
||||
}
|
||||
|
||||
public static final class Locale.Builder {
|
||||
ctor public Locale.Builder();
|
||||
method public java.util.Locale.Builder addUnicodeLocaleAttribute(java.lang.String);
|
||||
method public java.util.Locale build();
|
||||
method public java.util.Locale.Builder clear();
|
||||
method public java.util.Locale.Builder clearExtensions();
|
||||
method public java.util.Locale.Builder removeUnicodeLocaleAttribute(java.lang.String);
|
||||
method public java.util.Locale.Builder setExtension(char, java.lang.String);
|
||||
method public java.util.Locale.Builder setLanguage(java.lang.String);
|
||||
method public java.util.Locale.Builder setLanguageTag(java.lang.String);
|
||||
method public java.util.Locale.Builder setLocale(java.util.Locale);
|
||||
method public java.util.Locale.Builder setRegion(java.lang.String);
|
||||
method public java.util.Locale.Builder setScript(java.lang.String);
|
||||
method public java.util.Locale.Builder setUnicodeLocaleKeyword(java.lang.String, java.lang.String);
|
||||
method public java.util.Locale.Builder setVariant(java.lang.String);
|
||||
}
|
||||
|
||||
public abstract interface Map {
|
||||
method public abstract void clear();
|
||||
method public abstract boolean containsKey(java.lang.Object);
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.net.wifi.IWifiScanner;
|
||||
import android.net.wifi.WifiScanner;
|
||||
import android.os.Build;
|
||||
|
||||
import android.service.persistentdata.IPersistentDataBlockService;
|
||||
import android.service.persistentdata.PersistentDataBlockManager;
|
||||
import com.android.internal.policy.PolicyManager;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
@@ -733,7 +735,14 @@ class ContextImpl extends Context {
|
||||
public Object createService(ContextImpl ctx) {
|
||||
IBinder b = ServiceManager.getService(JOB_SCHEDULER_SERVICE);
|
||||
return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
|
||||
}});
|
||||
}});
|
||||
|
||||
registerService(PERSISTENT_DATA_BLOCK_SERVICE, new ServiceFetcher() {
|
||||
public Object createService(ContextImpl ctx) {
|
||||
IBinder b = ServiceManager.getService(PERSISTENT_DATA_BLOCK_SERVICE);
|
||||
return new PersistentDataBlockManager(
|
||||
IPersistentDataBlockService.Stub.asInterface(b));
|
||||
}});
|
||||
}
|
||||
|
||||
static ContextImpl getImpl(Context context) {
|
||||
|
||||
@@ -2800,6 +2800,16 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a {@link
|
||||
* android.service.persistentdata.PersistentDataBlockManager} instance retrieving
|
||||
* a file descriptor for a persistent data block.
|
||||
* @see #getSystemService
|
||||
* @see android.service.persistentdata.PersistentDataBlockManager
|
||||
* @hide
|
||||
*/
|
||||
public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
|
||||
|
||||
/**
|
||||
* Determine whether the given permission is allowed for a particular
|
||||
* process and user ID running in the system.
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package android.service.persistentdata;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
/**
|
||||
* Internal interface through which to communicate to the
|
||||
* PersistentDataBlockService. The persistent data block allows writing
|
||||
* raw data and setting the OEM unlock enabled/disabled bit contained
|
||||
* in the partition.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface IPersistentDataBlockService {
|
||||
int write(in byte[] data);
|
||||
int read(out byte[] data);
|
||||
int getDataBlockSize();
|
||||
|
||||
void setOemUnlockEnabled(boolean enabled);
|
||||
boolean getOemUnlockEnabled();
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package android.service.persistentdata;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
* Interface for reading and writing data blocks to a persistent partition.
|
||||
*
|
||||
* Allows writing one block at a time. Namely, each time
|
||||
* {@link android.service.persistentdata.PersistentDataBlockManager}.write(byte[] data)
|
||||
* is called, it will overwite the data that was previously written on the block.
|
||||
*
|
||||
* Clients can query the size of the currently written block via
|
||||
* {@link android.service.persistentdata.PersistentDataBlockManager}.getTotalDataSize().
|
||||
*
|
||||
* Clients can any number of bytes from the currently written block up to its total size by invoking
|
||||
* {@link android.service.persistentdata.PersistentDataBlockManager}.read(byte[] data).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class PersistentDataBlockManager {
|
||||
private static final String TAG = PersistentDataBlockManager.class.getSimpleName();
|
||||
private IPersistentDataBlockService sService;
|
||||
|
||||
public PersistentDataBlockManager(IPersistentDataBlockService service) {
|
||||
sService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes {@code data} to the persistent partition. Previously written data
|
||||
* will be overwritten. This data will persist across factory resets.
|
||||
*
|
||||
* @param data the data to write
|
||||
*/
|
||||
public void write(byte[] data) {
|
||||
try {
|
||||
sService.write(data);
|
||||
} catch (RemoteException e) {
|
||||
onError("writing data");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to read {@code data.length} bytes into {@code data}. Call {@code getDataBlockSize()}
|
||||
* to determine the total size of the block currently residing in the persistent partition.
|
||||
*
|
||||
* @param data the buffer in which to read the data
|
||||
* @return the actual number of bytes read
|
||||
*/
|
||||
public int read(byte[] data) {
|
||||
try {
|
||||
return sService.read(data);
|
||||
} catch (RemoteException e) {
|
||||
onError("reading data");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the size of the block currently written to the persistent partition.
|
||||
*/
|
||||
public int getDataBlockSize() {
|
||||
try {
|
||||
return sService.getDataBlockSize();
|
||||
} catch (RemoteException e) {
|
||||
onError("getting data block size");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte enabling or disabling the ability to "OEM unlock" the device.
|
||||
*/
|
||||
public void setOemUnlockEnabled(boolean enabled) {
|
||||
try {
|
||||
sService.setOemUnlockEnabled(enabled);
|
||||
} catch (RemoteException e) {
|
||||
onError("setting OEM unlock enabled to " + enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not "OEM unlock" is enabled or disabled on this device.
|
||||
*/
|
||||
public boolean getOemUnlockEnabled() {
|
||||
try {
|
||||
return sService.getOemUnlockEnabled();
|
||||
} catch (RemoteException e) {
|
||||
onError("getting OEM unlock enabled bit");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void onError(String msg) {
|
||||
Slog.v(TAG, "Remote exception while " + msg);
|
||||
}
|
||||
}
|
||||
@@ -1075,6 +1075,13 @@
|
||||
<permission android:name="android.permission.TV_INPUT_HARDWARE"
|
||||
android:protectionLevel="signatureOrSystem" />
|
||||
|
||||
<!-- @hide Allows enabling/disabling OEM unlock
|
||||
<p>Not for use by third-party applications. -->
|
||||
<permission android:name="android.permission.OEM_UNLOCK_STATE"
|
||||
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
|
||||
<!-- =========================================== -->
|
||||
<!-- Permissions associated with audio capture -->
|
||||
<!-- =========================================== -->
|
||||
|
||||
@@ -1610,12 +1610,15 @@
|
||||
-->
|
||||
</string-array>
|
||||
|
||||
<!-- Flag indicating apps will skip sending hold request before merge. In this case
|
||||
IMS service implementation will do both.i.e.hold followed by merge. -->
|
||||
<!-- Flag indicating which package name can access the persistent data partition -->
|
||||
<string name="config_persistentDataPackageName" translatable="false"></string>
|
||||
|
||||
<!-- Flag indicating apps will skip sending hold request before merge. In this case
|
||||
IMS service implementation will do both.i.e.hold followed by merge. -->
|
||||
<bool name="skipHoldBeforeMerge">true</bool>
|
||||
|
||||
<!-- Flag indicating emergency calls will always use IMS irrespective of the state of
|
||||
the IMS connection -->
|
||||
the IMS connection -->
|
||||
<bool name="useImsAlwaysForEmergencyCall">true</bool>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1668,6 +1668,7 @@
|
||||
<java-symbol type="string" name="config_customAdbPublicKeyConfirmationComponent" />
|
||||
<java-symbol type="string" name="config_customVpnConfirmDialogComponent" />
|
||||
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
|
||||
<java-symbol type="string" name="config_persistentDataPackageName" />
|
||||
|
||||
<java-symbol type="layout" name="resolver_list" />
|
||||
<java-symbol type="id" name="resolver_list" />
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
package com.android.server;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
import android.service.persistentdata.IPersistentDataBlockService;
|
||||
import android.util.Log;
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
/**
|
||||
* Service for reading and writing blocks to a persistent partition.
|
||||
* This data will live across factory resets.
|
||||
*
|
||||
* Allows writing one block at a time. Namely, each time
|
||||
* {@link android.service.persistentdata.IPersistentDataBlockService}.write(byte[] data)
|
||||
* is called, it will overwite the data that was previously written on the block.
|
||||
*
|
||||
* Clients can query the size of the currently written block via
|
||||
* {@link android.service.persistentdata.IPersistentDataBlockService}.getTotalDataSize().
|
||||
*
|
||||
* Clients can any number of bytes from the currently written block up to its total size by invoking
|
||||
* {@link android.service.persistentdata.IPersistentDataBlockService}.read(byte[] data)
|
||||
*/
|
||||
public class PersistentDataBlockService extends SystemService {
|
||||
private static final String TAG = PersistentDataBlockService.class.getSimpleName();
|
||||
|
||||
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
|
||||
private static final int HEADER_SIZE = 8;
|
||||
private static final int BLOCK_ID = 0x1990;
|
||||
|
||||
private final Context mContext;
|
||||
private final String mDataBlockFile;
|
||||
private long mBlockDeviceSize;
|
||||
|
||||
private final int mAllowedUid;
|
||||
|
||||
public PersistentDataBlockService(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
|
||||
mBlockDeviceSize = 0; // Load lazily
|
||||
String allowedPackage = context.getResources()
|
||||
.getString(R.string.config_persistentDataPackageName);
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
int allowedUid = -1;
|
||||
try {
|
||||
allowedUid = pm.getPackageUid(allowedPackage,
|
||||
Binder.getCallingUserHandle().getIdentifier());
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// not expected
|
||||
Log.e(TAG, "not able to find package " + allowedPackage, e);
|
||||
}
|
||||
|
||||
mAllowedUid = allowedUid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(Context.PERSISTENT_DATA_BLOCK_SERVICE, mService);
|
||||
}
|
||||
|
||||
private void enforceOemUnlockPermission() {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.OEM_UNLOCK_STATE,
|
||||
"Can't access OEM unlock state");
|
||||
}
|
||||
|
||||
private void enforceUid(int callingUid) {
|
||||
if (callingUid != mAllowedUid) {
|
||||
throw new SecurityException("uid " + callingUid + " not allowed to access PST");
|
||||
}
|
||||
}
|
||||
|
||||
private int getTotalDataSize(DataInputStream inputStream) throws IOException {
|
||||
int totalDataSize;
|
||||
int blockId = inputStream.readInt();
|
||||
if (blockId == BLOCK_ID) {
|
||||
totalDataSize = inputStream.readInt();
|
||||
} else {
|
||||
totalDataSize = 0;
|
||||
}
|
||||
return totalDataSize;
|
||||
}
|
||||
|
||||
private long maybeReadBlockDeviceSize() {
|
||||
synchronized (this) {
|
||||
if (mBlockDeviceSize == 0) {
|
||||
mBlockDeviceSize = getBlockDeviceSize(mDataBlockFile);
|
||||
}
|
||||
}
|
||||
|
||||
return mBlockDeviceSize;
|
||||
}
|
||||
|
||||
private native long getBlockDeviceSize(String path);
|
||||
|
||||
private final IBinder mService = new IPersistentDataBlockService.Stub() {
|
||||
@Override
|
||||
public int write(byte[] data) throws RemoteException {
|
||||
enforceUid(Binder.getCallingUid());
|
||||
|
||||
// Need to ensure we don't write over the last byte
|
||||
if (data.length > maybeReadBlockDeviceSize() - HEADER_SIZE - 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DataOutputStream outputStream;
|
||||
try {
|
||||
outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "partition not available?", e);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ByteBuffer headerAndData = ByteBuffer.allocate(data.length + HEADER_SIZE);
|
||||
headerAndData.putInt(BLOCK_ID);
|
||||
headerAndData.putInt(data.length);
|
||||
headerAndData.put(data);
|
||||
|
||||
try {
|
||||
outputStream.write(headerAndData.array());
|
||||
return data.length;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed writing to the persistent data block", e);
|
||||
return -1;
|
||||
} finally {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed closing output stream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] data) {
|
||||
enforceUid(Binder.getCallingUid());
|
||||
|
||||
DataInputStream inputStream;
|
||||
try {
|
||||
inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "partition not available?", e);
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
int totalDataSize = getTotalDataSize(inputStream);
|
||||
return inputStream.read(data, 0,
|
||||
(data.length > totalDataSize) ? totalDataSize : data.length);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed to read data", e);
|
||||
return -1;
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed to close OutputStream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOemUnlockEnabled(boolean enabled) {
|
||||
enforceOemUnlockPermission();
|
||||
FileOutputStream outputStream;
|
||||
try {
|
||||
outputStream = new FileOutputStream(new File(mDataBlockFile));
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "parition not available", e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
FileChannel channel = outputStream.getChannel();
|
||||
|
||||
channel.position(maybeReadBlockDeviceSize() - 1);
|
||||
|
||||
ByteBuffer data = ByteBuffer.allocate(1);
|
||||
data.put(enabled ? (byte) 1 : (byte) 0);
|
||||
data.flip();
|
||||
|
||||
channel.write(data);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "unable to access persistent partition", e);
|
||||
} finally {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed to close OutputStream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getOemUnlockEnabled() {
|
||||
enforceOemUnlockPermission();
|
||||
DataInputStream inputStream;
|
||||
try {
|
||||
inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "partition not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
inputStream.skip(maybeReadBlockDeviceSize() - 1);
|
||||
return inputStream.readByte() != 0;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "unable to access persistent partition", e);
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed to close OutputStream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataBlockSize() {
|
||||
enforceUid(Binder.getCallingUid());
|
||||
|
||||
DataInputStream inputStream;
|
||||
try {
|
||||
inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "partition not available");
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return getTotalDataSize(inputStream);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "error reading data block size");
|
||||
return 0;
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed to close OutputStream");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -26,6 +26,7 @@ LOCAL_SRC_FILES += \
|
||||
$(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
|
||||
$(LOCAL_REL_DIR)/onload.cpp
|
||||
|
||||
include external/stlport/libstlport.mk
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source 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.
|
||||
*/
|
||||
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
#include <JNIHelp.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include <utils/misc.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
uint64_t get_block_device_size(int fd)
|
||||
{
|
||||
uint64_t size = 0;
|
||||
int ret;
|
||||
|
||||
ret = ioctl(fd, BLKGETSIZE64, &size);
|
||||
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static jlong com_android_server_PeristentDataBlockService_getBlockDeviceSize(JNIEnv *env, jclass, jstring jpath) {
|
||||
const char *path = env->GetStringUTFChars(jpath, 0);
|
||||
int fd = open(path, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
return get_block_device_size(fd);
|
||||
}
|
||||
|
||||
static JNINativeMethod sMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{"getBlockDeviceSize", "(Ljava/lang/String;)J", (void*)com_android_server_PeristentDataBlockService_getBlockDeviceSize},
|
||||
};
|
||||
|
||||
int register_android_server_PersistentDataBlockService(JNIEnv* env)
|
||||
{
|
||||
return jniRegisterNativeMethods(env, "com/android/server/PersistentDataBlockService",
|
||||
sMethods, NELEM(sMethods));
|
||||
}
|
||||
|
||||
} /* namespace android */
|
||||
@@ -41,6 +41,7 @@ int register_android_server_dreams_McuHal(JNIEnv* env);
|
||||
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
|
||||
int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
|
||||
int register_android_server_tv_TvInputHal(JNIEnv* env);
|
||||
int register_android_server_PersistentDataBlockService(JNIEnv* env);
|
||||
};
|
||||
|
||||
using namespace android;
|
||||
@@ -77,6 +78,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
register_android_server_hdmi_HdmiCecController(env);
|
||||
register_android_server_hdmi_HdmiMhlController(env);
|
||||
register_android_server_tv_TvInputHal(env);
|
||||
register_android_server_PersistentDataBlockService(env);
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
@@ -135,6 +135,7 @@ public final class SystemServer {
|
||||
"com.android.server.ethernet.EthernetService";
|
||||
private static final String JOB_SCHEDULER_SERVICE_CLASS =
|
||||
"com.android.server.job.JobSchedulerService";
|
||||
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
|
||||
|
||||
private final int mFactoryTestMode;
|
||||
private Timer mProfilerSnapshotTimer;
|
||||
@@ -574,6 +575,10 @@ public final class SystemServer {
|
||||
reportWtf("starting LockSettingsService service", e);
|
||||
}
|
||||
|
||||
if (!SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("")) {
|
||||
mSystemServiceManager.startService(PersistentDataBlockService.class);
|
||||
}
|
||||
|
||||
// Always start the Device Policy Manager, so that the API is compatible with
|
||||
// API8.
|
||||
mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
|
||||
|
||||
Reference in New Issue
Block a user