blob: 96bab0ee9ffa58baa4664a349cc395eb02944405 [file] [log] [blame]
Andres Morales963295e2014-07-10 15:40:24 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andres Morales68d4acd2014-07-01 19:40:41 -070017package com.android.server;
18
19import android.Manifest;
Guang Zhu514c5802014-09-12 15:14:00 -070020import android.app.ActivityManager;
Andres Morales68d4acd2014-07-01 19:40:41 -070021import android.content.Context;
22import android.content.pm.PackageManager;
23import android.os.Binder;
24import android.os.IBinder;
25import android.os.RemoteException;
26import android.os.SystemProperties;
Andres Morales6429f312014-08-04 16:35:15 -070027import android.os.UserHandle;
Xiaohui Chenf0660782015-09-02 14:25:19 -070028import android.os.UserManager;
Andres Morales68d4acd2014-07-01 19:40:41 -070029import android.service.persistentdata.IPersistentDataBlockService;
Andres Morales74e9b182016-02-22 12:33:33 -080030import android.service.persistentdata.PersistentDataBlockManager;
Andres Morales963295e2014-07-10 15:40:24 -070031import android.util.Slog;
Guang Zhu514c5802014-09-12 15:14:00 -070032
Andres Morales68d4acd2014-07-01 19:40:41 -070033import com.android.internal.R;
Charles Hef6f1d622016-12-01 19:22:33 +000034import com.android.internal.annotations.GuardedBy;
Guang Zhu514c5802014-09-12 15:14:00 -070035
Andres Morales963295e2014-07-10 15:40:24 -070036import libcore.io.IoUtils;
Andres Morales68d4acd2014-07-01 19:40:41 -070037
38import java.io.DataInputStream;
39import java.io.DataOutputStream;
40import java.io.File;
41import java.io.FileInputStream;
42import java.io.FileNotFoundException;
43import java.io.FileOutputStream;
44import java.io.IOException;
45import java.nio.ByteBuffer;
46import java.nio.channels.FileChannel;
Andres Morales28301302014-11-12 07:56:46 -080047import java.security.MessageDigest;
48import java.security.NoSuchAlgorithmException;
49import java.util.Arrays;
Andres Morales68d4acd2014-07-01 19:40:41 -070050
51/**
52 * Service for reading and writing blocks to a persistent partition.
Andres Morales963295e2014-07-10 15:40:24 -070053 * This data will live across factory resets not initiated via the Settings UI.
54 * When a device is factory reset through Settings this data is wiped.
Andres Morales68d4acd2014-07-01 19:40:41 -070055 *
Charles Hea629c772016-11-24 14:05:00 +000056 * Allows writing one block at a time. Namely, each time {@link IPersistentDataBlockService#write}
57 * is called, it will overwrite the data that was previously written on the block.
Andres Morales68d4acd2014-07-01 19:40:41 -070058 *
59 * Clients can query the size of the currently written block via
Charles Hea629c772016-11-24 14:05:00 +000060 * {@link IPersistentDataBlockService#getDataBlockSize}
Andres Morales68d4acd2014-07-01 19:40:41 -070061 *
Charles Hea629c772016-11-24 14:05:00 +000062 * Clients can read any number of bytes from the currently written block up to its total size by
63 * invoking {@link IPersistentDataBlockService#read}
Andres Morales68d4acd2014-07-01 19:40:41 -070064 */
65public class PersistentDataBlockService extends SystemService {
66 private static final String TAG = PersistentDataBlockService.class.getSimpleName();
67
68 private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
69 private static final int HEADER_SIZE = 8;
Andres Morales963295e2014-07-10 15:40:24 -070070 // Magic number to mark block device as adhering to the format consumed by this service
Andres Morales28301302014-11-12 07:56:46 -080071 private static final int PARTITION_TYPE_MARKER = 0x19901873;
Andres Morales963295e2014-07-10 15:40:24 -070072 // Limit to 100k as blocks larger than this might cause strain on Binder.
Andres Morales963295e2014-07-10 15:40:24 -070073 private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
Andres Morales28301302014-11-12 07:56:46 -080074 public static final int DIGEST_SIZE_BYTES = 32;
Andres Morales5ca4cc52015-03-19 16:37:54 -070075 private static final String OEM_UNLOCK_PROP = "sys.oem_unlock_allowed";
Andres Morales74e9b182016-02-22 12:33:33 -080076 private static final String FLASH_LOCK_PROP = "ro.boot.flash.locked";
77 private static final String FLASH_LOCK_LOCKED = "1";
78 private static final String FLASH_LOCK_UNLOCKED = "0";
Andres Morales68d4acd2014-07-01 19:40:41 -070079
80 private final Context mContext;
81 private final String mDataBlockFile;
Andres Morales963295e2014-07-10 15:40:24 -070082 private final Object mLock = new Object();
Andres Morales6429f312014-08-04 16:35:15 -070083
Andres Moralesa31c23d2014-10-30 15:31:31 -070084 private int mAllowedUid = -1;
Andres Morales963295e2014-07-10 15:40:24 -070085 private long mBlockDeviceSize;
Charles Hef6f1d622016-12-01 19:22:33 +000086
87 @GuardedBy("mLock")
Charles Hea629c772016-11-24 14:05:00 +000088 private boolean mIsWritable = true;
Andres Morales68d4acd2014-07-01 19:40:41 -070089
90 public PersistentDataBlockService(Context context) {
91 super(context);
92 mContext = context;
93 mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
Andres Morales963295e2014-07-10 15:40:24 -070094 mBlockDeviceSize = -1; // Load lazily
Xiaohui Chenf0660782015-09-02 14:25:19 -070095 mAllowedUid = getAllowedUid(UserHandle.USER_SYSTEM);
Andres Morales6429f312014-08-04 16:35:15 -070096 }
97
Andres Moralesa31c23d2014-10-30 15:31:31 -070098 private int getAllowedUid(int userHandle) {
Andres Morales6429f312014-08-04 16:35:15 -070099 String allowedPackage = mContext.getResources()
Andres Morales68d4acd2014-07-01 19:40:41 -0700100 .getString(R.string.config_persistentDataPackageName);
101 PackageManager pm = mContext.getPackageManager();
102 int allowedUid = -1;
103 try {
Jeff Sharkeyc5967e92016-01-07 18:50:29 -0700104 allowedUid = pm.getPackageUidAsUser(allowedPackage,
105 PackageManager.MATCH_SYSTEM_ONLY, userHandle);
Andres Morales68d4acd2014-07-01 19:40:41 -0700106 } catch (PackageManager.NameNotFoundException e) {
107 // not expected
Andres Morales963295e2014-07-10 15:40:24 -0700108 Slog.e(TAG, "not able to find package " + allowedPackage, e);
Andres Morales68d4acd2014-07-01 19:40:41 -0700109 }
Andres Moralesa31c23d2014-10-30 15:31:31 -0700110 return allowedUid;
Andres Morales68d4acd2014-07-01 19:40:41 -0700111 }
112
113 @Override
114 public void onStart() {
Andres Morales28301302014-11-12 07:56:46 -0800115 enforceChecksumValidity();
Andres Morales1ce7d172015-01-07 14:24:57 -0800116 formatIfOemUnlockEnabled();
Andres Morales68d4acd2014-07-01 19:40:41 -0700117 publishBinderService(Context.PERSISTENT_DATA_BLOCK_SERVICE, mService);
118 }
119
Andres Morales1ce7d172015-01-07 14:24:57 -0800120 private void formatIfOemUnlockEnabled() {
Andres Morales5ca4cc52015-03-19 16:37:54 -0700121 boolean enabled = doGetOemUnlockEnabled();
122 if (enabled) {
Andres Morales1ce7d172015-01-07 14:24:57 -0800123 synchronized (mLock) {
Andres Moralesc8f952c2015-03-19 08:34:55 -0700124 formatPartitionLocked(true);
Andres Morales1ce7d172015-01-07 14:24:57 -0800125 }
126 }
Andres Morales5ca4cc52015-03-19 16:37:54 -0700127
128 SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
Andres Morales1ce7d172015-01-07 14:24:57 -0800129 }
130
Amith Yamasanid2b21042016-06-03 10:12:47 -0700131 private void enforceOemUnlockReadPermission() {
132 if (mContext.checkCallingOrSelfPermission(Manifest.permission.READ_OEM_UNLOCK_STATE)
133 == PackageManager.PERMISSION_DENIED
134 && mContext.checkCallingOrSelfPermission(Manifest.permission.OEM_UNLOCK_STATE)
135 == PackageManager.PERMISSION_DENIED) {
136 throw new SecurityException("Can't access OEM unlock state. Requires "
137 + "READ_OEM_UNLOCK_STATE or OEM_UNLOCK_STATE permission.");
138 }
139 }
140
141 private void enforceOemUnlockWritePermission() {
Andres Morales68d4acd2014-07-01 19:40:41 -0700142 mContext.enforceCallingOrSelfPermission(
143 Manifest.permission.OEM_UNLOCK_STATE,
Amith Yamasanid2b21042016-06-03 10:12:47 -0700144 "Can't modify OEM unlock state");
Andres Morales68d4acd2014-07-01 19:40:41 -0700145 }
146
147 private void enforceUid(int callingUid) {
Andres Moralesa31c23d2014-10-30 15:31:31 -0700148 if (callingUid != mAllowedUid) {
Andres Morales68d4acd2014-07-01 19:40:41 -0700149 throw new SecurityException("uid " + callingUid + " not allowed to access PST");
150 }
151 }
152
Xiaohui Chenf0660782015-09-02 14:25:19 -0700153 private void enforceIsAdmin() {
154 final int userId = UserHandle.getCallingUserId();
155 final boolean isAdmin = UserManager.get(mContext).isUserAdmin(userId);
156 if (!isAdmin) {
157 throw new SecurityException(
158 "Only the Admin user is allowed to change OEM unlock state");
Andres Moralesa31c23d2014-10-30 15:31:31 -0700159 }
160 }
Mahaver Chopra830e32c2016-05-17 18:53:09 +0100161
Mahaver Chopra3d9805d2016-07-07 16:25:05 +0100162 private void enforceUserRestriction(String userRestriction) {
163 if (UserManager.get(mContext).hasUserRestriction(userRestriction)) {
164 throw new SecurityException(
165 "OEM unlock is disallowed by user restriction: " + userRestriction);
Mahaver Chopra830e32c2016-05-17 18:53:09 +0100166 }
167 }
168
Andres Morales963295e2014-07-10 15:40:24 -0700169 private int getTotalDataSizeLocked(DataInputStream inputStream) throws IOException {
Andres Morales28301302014-11-12 07:56:46 -0800170 // skip over checksum
171 inputStream.skipBytes(DIGEST_SIZE_BYTES);
172
Andres Morales68d4acd2014-07-01 19:40:41 -0700173 int totalDataSize;
174 int blockId = inputStream.readInt();
Andres Morales963295e2014-07-10 15:40:24 -0700175 if (blockId == PARTITION_TYPE_MARKER) {
Andres Morales68d4acd2014-07-01 19:40:41 -0700176 totalDataSize = inputStream.readInt();
177 } else {
178 totalDataSize = 0;
179 }
180 return totalDataSize;
181 }
182
Andres Morales963295e2014-07-10 15:40:24 -0700183 private long getBlockDeviceSize() {
184 synchronized (mLock) {
185 if (mBlockDeviceSize == -1) {
186 mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
Andres Morales68d4acd2014-07-01 19:40:41 -0700187 }
188 }
189
190 return mBlockDeviceSize;
191 }
192
Andres Morales28301302014-11-12 07:56:46 -0800193 private boolean enforceChecksumValidity() {
194 byte[] storedDigest = new byte[DIGEST_SIZE_BYTES];
195
196 synchronized (mLock) {
197 byte[] digest = computeDigestLocked(storedDigest);
198 if (digest == null || !Arrays.equals(storedDigest, digest)) {
199 Slog.i(TAG, "Formatting FRP partition...");
Andres Moralesc8f952c2015-03-19 08:34:55 -0700200 formatPartitionLocked(false);
Andres Morales28301302014-11-12 07:56:46 -0800201 return false;
202 }
203 }
204
205 return true;
206 }
207
208 private boolean computeAndWriteDigestLocked() {
209 byte[] digest = computeDigestLocked(null);
210 if (digest != null) {
211 DataOutputStream outputStream;
212 try {
213 outputStream = new DataOutputStream(
214 new FileOutputStream(new File(mDataBlockFile)));
215 } catch (FileNotFoundException e) {
216 Slog.e(TAG, "partition not available?", e);
217 return false;
218 }
219
220 try {
221 outputStream.write(digest, 0, DIGEST_SIZE_BYTES);
222 outputStream.flush();
223 } catch (IOException e) {
224 Slog.e(TAG, "failed to write block checksum", e);
225 return false;
226 } finally {
227 IoUtils.closeQuietly(outputStream);
228 }
229 return true;
230 } else {
231 return false;
232 }
233 }
234
235 private byte[] computeDigestLocked(byte[] storedDigest) {
236 DataInputStream inputStream;
237 try {
238 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
239 } catch (FileNotFoundException e) {
240 Slog.e(TAG, "partition not available?", e);
241 return null;
242 }
243
244 MessageDigest md;
245 try {
246 md = MessageDigest.getInstance("SHA-256");
247 } catch (NoSuchAlgorithmException e) {
248 // won't ever happen -- every implementation is required to support SHA-256
249 Slog.e(TAG, "SHA-256 not supported?", e);
250 IoUtils.closeQuietly(inputStream);
251 return null;
252 }
253
254 try {
255 if (storedDigest != null && storedDigest.length == DIGEST_SIZE_BYTES) {
256 inputStream.read(storedDigest);
257 } else {
258 inputStream.skipBytes(DIGEST_SIZE_BYTES);
259 }
260
261 int read;
262 byte[] data = new byte[1024];
263 md.update(data, 0, DIGEST_SIZE_BYTES); // include 0 checksum in digest
264 while ((read = inputStream.read(data)) != -1) {
265 md.update(data, 0, read);
266 }
267 } catch (IOException e) {
268 Slog.e(TAG, "failed to read partition", e);
269 return null;
270 } finally {
271 IoUtils.closeQuietly(inputStream);
272 }
273
274 return md.digest();
275 }
276
Andres Moralesc8f952c2015-03-19 08:34:55 -0700277 private void formatPartitionLocked(boolean setOemUnlockEnabled) {
Andres Morales28301302014-11-12 07:56:46 -0800278 DataOutputStream outputStream;
279 try {
280 outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
281 } catch (FileNotFoundException e) {
282 Slog.e(TAG, "partition not available?", e);
283 return;
284 }
285
286 byte[] data = new byte[DIGEST_SIZE_BYTES];
287 try {
288 outputStream.write(data, 0, DIGEST_SIZE_BYTES);
289 outputStream.writeInt(PARTITION_TYPE_MARKER);
290 outputStream.writeInt(0); // data size
291 outputStream.flush();
292 } catch (IOException e) {
293 Slog.e(TAG, "failed to format block", e);
294 return;
295 } finally {
296 IoUtils.closeQuietly(outputStream);
297 }
298
Andres Moralesc8f952c2015-03-19 08:34:55 -0700299 doSetOemUnlockEnabledLocked(setOemUnlockEnabled);
Andres Morales28301302014-11-12 07:56:46 -0800300 computeAndWriteDigestLocked();
301 }
302
303 private void doSetOemUnlockEnabledLocked(boolean enabled) {
304 FileOutputStream outputStream;
305 try {
306 outputStream = new FileOutputStream(new File(mDataBlockFile));
307 } catch (FileNotFoundException e) {
308 Slog.e(TAG, "partition not available", e);
309 return;
310 }
311
312 try {
313 FileChannel channel = outputStream.getChannel();
314
315 channel.position(getBlockDeviceSize() - 1);
316
317 ByteBuffer data = ByteBuffer.allocate(1);
318 data.put(enabled ? (byte) 1 : (byte) 0);
319 data.flip();
320 channel.write(data);
321 outputStream.flush();
322 } catch (IOException e) {
323 Slog.e(TAG, "unable to access persistent partition", e);
324 return;
325 } finally {
Andres Morales5ca4cc52015-03-19 16:37:54 -0700326 SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
Andres Morales28301302014-11-12 07:56:46 -0800327 IoUtils.closeQuietly(outputStream);
328 }
329 }
330
Andres Morales1ce7d172015-01-07 14:24:57 -0800331 private boolean doGetOemUnlockEnabled() {
332 DataInputStream inputStream;
333 try {
334 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
335 } catch (FileNotFoundException e) {
336 Slog.e(TAG, "partition not available");
337 return false;
338 }
339
340 try {
341 synchronized (mLock) {
342 inputStream.skip(getBlockDeviceSize() - 1);
343 return inputStream.readByte() != 0;
344 }
345 } catch (IOException e) {
346 Slog.e(TAG, "unable to access persistent partition", e);
347 return false;
348 } finally {
349 IoUtils.closeQuietly(inputStream);
350 }
351 }
352
Andres Morales963295e2014-07-10 15:40:24 -0700353 private native long nativeGetBlockDeviceSize(String path);
354 private native int nativeWipe(String path);
Andres Morales68d4acd2014-07-01 19:40:41 -0700355
356 private final IBinder mService = new IPersistentDataBlockService.Stub() {
357 @Override
358 public int write(byte[] data) throws RemoteException {
359 enforceUid(Binder.getCallingUid());
360
361 // Need to ensure we don't write over the last byte
Andres Morales963295e2014-07-10 15:40:24 -0700362 long maxBlockSize = getBlockDeviceSize() - HEADER_SIZE - 1;
363 if (data.length > maxBlockSize) {
364 // partition is ~500k so shouldn't be a problem to downcast
365 return (int) -maxBlockSize;
Andres Morales68d4acd2014-07-01 19:40:41 -0700366 }
367
368 DataOutputStream outputStream;
369 try {
370 outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
371 } catch (FileNotFoundException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700372 Slog.e(TAG, "partition not available?", e);
Andres Morales68d4acd2014-07-01 19:40:41 -0700373 return -1;
374 }
375
376 ByteBuffer headerAndData = ByteBuffer.allocate(data.length + HEADER_SIZE);
Andres Morales963295e2014-07-10 15:40:24 -0700377 headerAndData.putInt(PARTITION_TYPE_MARKER);
Andres Morales68d4acd2014-07-01 19:40:41 -0700378 headerAndData.putInt(data.length);
379 headerAndData.put(data);
380
Andres Morales28301302014-11-12 07:56:46 -0800381 synchronized (mLock) {
Charles Hea629c772016-11-24 14:05:00 +0000382 if (!mIsWritable) {
383 IoUtils.closeQuietly(outputStream);
384 return -1;
385 }
386
Andres Morales68d4acd2014-07-01 19:40:41 -0700387 try {
Andres Morales28301302014-11-12 07:56:46 -0800388 byte[] checksum = new byte[DIGEST_SIZE_BYTES];
389 outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
390 outputStream.write(headerAndData.array());
391 outputStream.flush();
Andres Morales68d4acd2014-07-01 19:40:41 -0700392 } catch (IOException e) {
Andres Morales28301302014-11-12 07:56:46 -0800393 Slog.e(TAG, "failed writing to the persistent data block", e);
394 return -1;
395 } finally {
396 IoUtils.closeQuietly(outputStream);
397 }
398
399 if (computeAndWriteDigestLocked()) {
400 return data.length;
401 } else {
402 return -1;
Andres Morales68d4acd2014-07-01 19:40:41 -0700403 }
404 }
405 }
406
407 @Override
Andres Morales963295e2014-07-10 15:40:24 -0700408 public byte[] read() {
Andres Morales68d4acd2014-07-01 19:40:41 -0700409 enforceUid(Binder.getCallingUid());
Andres Morales28301302014-11-12 07:56:46 -0800410 if (!enforceChecksumValidity()) {
411 return new byte[0];
412 }
Andres Morales68d4acd2014-07-01 19:40:41 -0700413
414 DataInputStream inputStream;
415 try {
416 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
417 } catch (FileNotFoundException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700418 Slog.e(TAG, "partition not available?", e);
419 return null;
Andres Morales68d4acd2014-07-01 19:40:41 -0700420 }
421
422 try {
Andres Morales963295e2014-07-10 15:40:24 -0700423 synchronized (mLock) {
424 int totalDataSize = getTotalDataSizeLocked(inputStream);
425
426 if (totalDataSize == 0) {
427 return new byte[0];
428 }
429
430 byte[] data = new byte[totalDataSize];
431 int read = inputStream.read(data, 0, totalDataSize);
432 if (read < totalDataSize) {
433 // something went wrong, not returning potentially corrupt data
434 Slog.e(TAG, "failed to read entire data block. bytes read: " +
435 read + "/" + totalDataSize);
436 return null;
437 }
438 return data;
439 }
Andres Morales68d4acd2014-07-01 19:40:41 -0700440 } catch (IOException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700441 Slog.e(TAG, "failed to read data", e);
442 return null;
Andres Morales68d4acd2014-07-01 19:40:41 -0700443 } finally {
444 try {
445 inputStream.close();
446 } catch (IOException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700447 Slog.e(TAG, "failed to close OutputStream");
448 }
449 }
450 }
451
452 @Override
453 public void wipe() {
Amith Yamasanid2b21042016-06-03 10:12:47 -0700454 enforceOemUnlockWritePermission();
Andres Morales963295e2014-07-10 15:40:24 -0700455
456 synchronized (mLock) {
457 int ret = nativeWipe(mDataBlockFile);
458
459 if (ret < 0) {
460 Slog.e(TAG, "failed to wipe persistent partition");
Charles Hea629c772016-11-24 14:05:00 +0000461 } else {
462 mIsWritable = false;
463 Slog.i(TAG, "persistent partition now wiped and unwritable");
Andres Morales68d4acd2014-07-01 19:40:41 -0700464 }
465 }
466 }
467
468 @Override
Steven Ngdc20ba62016-04-26 18:19:04 +0100469 public void setOemUnlockEnabled(boolean enabled) throws SecurityException {
Guang Zhu514c5802014-09-12 15:14:00 -0700470 // do not allow monkey to flip the flag
471 if (ActivityManager.isUserAMonkey()) {
472 return;
473 }
Steven Ngbfe1b042016-05-16 11:20:57 +0100474
Amith Yamasanid2b21042016-06-03 10:12:47 -0700475 enforceOemUnlockWritePermission();
Steven Ngbfe1b042016-05-16 11:20:57 +0100476 enforceIsAdmin();
477
Mahaver Chopra830e32c2016-05-17 18:53:09 +0100478 if (enabled) {
Mahaver Chopra3d9805d2016-07-07 16:25:05 +0100479 // Do not allow oem unlock to be enabled if it's disallowed by a user restriction.
480 enforceUserRestriction(UserManager.DISALLOW_OEM_UNLOCK);
481 enforceUserRestriction(UserManager.DISALLOW_FACTORY_RESET);
Mahaver Chopra830e32c2016-05-17 18:53:09 +0100482 }
Andres Morales28301302014-11-12 07:56:46 -0800483 synchronized (mLock) {
484 doSetOemUnlockEnabledLocked(enabled);
485 computeAndWriteDigestLocked();
Andres Morales68d4acd2014-07-01 19:40:41 -0700486 }
487 }
488
489 @Override
490 public boolean getOemUnlockEnabled() {
Amith Yamasanid2b21042016-06-03 10:12:47 -0700491 enforceOemUnlockReadPermission();
Andres Morales1ce7d172015-01-07 14:24:57 -0800492 return doGetOemUnlockEnabled();
Andres Morales68d4acd2014-07-01 19:40:41 -0700493 }
494
495 @Override
Andres Morales74e9b182016-02-22 12:33:33 -0800496 public int getFlashLockState() {
Amith Yamasanid2b21042016-06-03 10:12:47 -0700497 enforceOemUnlockReadPermission();
Andres Morales74e9b182016-02-22 12:33:33 -0800498 String locked = SystemProperties.get(FLASH_LOCK_PROP);
499 switch (locked) {
500 case FLASH_LOCK_LOCKED:
501 return PersistentDataBlockManager.FLASH_LOCK_LOCKED;
502 case FLASH_LOCK_UNLOCKED:
503 return PersistentDataBlockManager.FLASH_LOCK_UNLOCKED;
504 default:
505 return PersistentDataBlockManager.FLASH_LOCK_UNKNOWN;
506 }
507 }
508
509 @Override
Andres Morales68d4acd2014-07-01 19:40:41 -0700510 public int getDataBlockSize() {
Craig Lafayette66445a62015-03-27 09:01:43 -0400511 enforcePersistentDataBlockAccess();
Andres Morales68d4acd2014-07-01 19:40:41 -0700512
513 DataInputStream inputStream;
514 try {
515 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
516 } catch (FileNotFoundException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700517 Slog.e(TAG, "partition not available");
Andres Morales68d4acd2014-07-01 19:40:41 -0700518 return 0;
519 }
520
521 try {
Andres Morales963295e2014-07-10 15:40:24 -0700522 synchronized (mLock) {
523 return getTotalDataSizeLocked(inputStream);
524 }
Andres Morales68d4acd2014-07-01 19:40:41 -0700525 } catch (IOException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700526 Slog.e(TAG, "error reading data block size");
Andres Morales68d4acd2014-07-01 19:40:41 -0700527 return 0;
528 } finally {
Andres Morales963295e2014-07-10 15:40:24 -0700529 IoUtils.closeQuietly(inputStream);
Andres Morales68d4acd2014-07-01 19:40:41 -0700530 }
531 }
Andres Morales963295e2014-07-10 15:40:24 -0700532
Craig Lafayette66445a62015-03-27 09:01:43 -0400533 private void enforcePersistentDataBlockAccess() {
534 if (mContext.checkCallingPermission(Manifest.permission.ACCESS_PDB_STATE)
535 != PackageManager.PERMISSION_GRANTED) {
536 enforceUid(Binder.getCallingUid());
537 }
538 }
539
Andres Morales963295e2014-07-10 15:40:24 -0700540 @Override
541 public long getMaximumDataBlockSize() {
542 long actualSize = getBlockDeviceSize() - HEADER_SIZE - 1;
543 return actualSize <= MAX_DATA_BLOCK_SIZE ? actualSize : MAX_DATA_BLOCK_SIZE;
544 }
Andres Morales68d4acd2014-07-01 19:40:41 -0700545 };
546}