blob: 080b46c24a2fd636b84c654313b6345b67f3d218 [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;
Steven Ngdc20ba62016-04-26 18:19:04 +010029import android.provider.Settings;
Andres Morales68d4acd2014-07-01 19:40:41 -070030import android.service.persistentdata.IPersistentDataBlockService;
Andres Morales74e9b182016-02-22 12:33:33 -080031import android.service.persistentdata.PersistentDataBlockManager;
Andres Morales963295e2014-07-10 15:40:24 -070032import android.util.Slog;
Guang Zhu514c5802014-09-12 15:14:00 -070033
Andres Morales68d4acd2014-07-01 19:40:41 -070034import com.android.internal.R;
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 *
56 * Allows writing one block at a time. Namely, each time
57 * {@link android.service.persistentdata.IPersistentDataBlockService}.write(byte[] data)
58 * is called, it will overwite the data that was previously written on the block.
59 *
60 * Clients can query the size of the currently written block via
61 * {@link android.service.persistentdata.IPersistentDataBlockService}.getTotalDataSize().
62 *
63 * Clients can any number of bytes from the currently written block up to its total size by invoking
64 * {@link android.service.persistentdata.IPersistentDataBlockService}.read(byte[] data)
65 */
66public class PersistentDataBlockService extends SystemService {
67 private static final String TAG = PersistentDataBlockService.class.getSimpleName();
68
69 private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
70 private static final int HEADER_SIZE = 8;
Andres Morales963295e2014-07-10 15:40:24 -070071 // Magic number to mark block device as adhering to the format consumed by this service
Andres Morales28301302014-11-12 07:56:46 -080072 private static final int PARTITION_TYPE_MARKER = 0x19901873;
Andres Morales963295e2014-07-10 15:40:24 -070073 // Limit to 100k as blocks larger than this might cause strain on Binder.
Andres Morales963295e2014-07-10 15:40:24 -070074 private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
Andres Morales28301302014-11-12 07:56:46 -080075 public static final int DIGEST_SIZE_BYTES = 32;
Andres Morales5ca4cc52015-03-19 16:37:54 -070076 private static final String OEM_UNLOCK_PROP = "sys.oem_unlock_allowed";
Andres Morales74e9b182016-02-22 12:33:33 -080077 private static final String FLASH_LOCK_PROP = "ro.boot.flash.locked";
78 private static final String FLASH_LOCK_LOCKED = "1";
79 private static final String FLASH_LOCK_UNLOCKED = "0";
Andres Morales68d4acd2014-07-01 19:40:41 -070080
81 private final Context mContext;
82 private final String mDataBlockFile;
Andres Morales963295e2014-07-10 15:40:24 -070083 private final Object mLock = new Object();
Andres Morales6429f312014-08-04 16:35:15 -070084
Andres Moralesa31c23d2014-10-30 15:31:31 -070085 private int mAllowedUid = -1;
Andres Morales963295e2014-07-10 15:40:24 -070086 private long mBlockDeviceSize;
Andres Morales68d4acd2014-07-01 19:40:41 -070087
88 public PersistentDataBlockService(Context context) {
89 super(context);
90 mContext = context;
91 mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
Andres Morales963295e2014-07-10 15:40:24 -070092 mBlockDeviceSize = -1; // Load lazily
Xiaohui Chenf0660782015-09-02 14:25:19 -070093 mAllowedUid = getAllowedUid(UserHandle.USER_SYSTEM);
Andres Morales6429f312014-08-04 16:35:15 -070094 }
95
Andres Moralesa31c23d2014-10-30 15:31:31 -070096 private int getAllowedUid(int userHandle) {
Andres Morales6429f312014-08-04 16:35:15 -070097 String allowedPackage = mContext.getResources()
Andres Morales68d4acd2014-07-01 19:40:41 -070098 .getString(R.string.config_persistentDataPackageName);
99 PackageManager pm = mContext.getPackageManager();
100 int allowedUid = -1;
101 try {
Jeff Sharkeyc5967e92016-01-07 18:50:29 -0700102 allowedUid = pm.getPackageUidAsUser(allowedPackage,
103 PackageManager.MATCH_SYSTEM_ONLY, userHandle);
Andres Morales68d4acd2014-07-01 19:40:41 -0700104 } catch (PackageManager.NameNotFoundException e) {
105 // not expected
Andres Morales963295e2014-07-10 15:40:24 -0700106 Slog.e(TAG, "not able to find package " + allowedPackage, e);
Andres Morales68d4acd2014-07-01 19:40:41 -0700107 }
Andres Moralesa31c23d2014-10-30 15:31:31 -0700108 return allowedUid;
Andres Morales68d4acd2014-07-01 19:40:41 -0700109 }
110
111 @Override
112 public void onStart() {
Andres Morales28301302014-11-12 07:56:46 -0800113 enforceChecksumValidity();
Andres Morales1ce7d172015-01-07 14:24:57 -0800114 formatIfOemUnlockEnabled();
Andres Morales68d4acd2014-07-01 19:40:41 -0700115 publishBinderService(Context.PERSISTENT_DATA_BLOCK_SERVICE, mService);
116 }
117
Andres Morales1ce7d172015-01-07 14:24:57 -0800118 private void formatIfOemUnlockEnabled() {
Andres Morales5ca4cc52015-03-19 16:37:54 -0700119 boolean enabled = doGetOemUnlockEnabled();
120 if (enabled) {
Andres Morales1ce7d172015-01-07 14:24:57 -0800121 synchronized (mLock) {
Andres Moralesc8f952c2015-03-19 08:34:55 -0700122 formatPartitionLocked(true);
Andres Morales1ce7d172015-01-07 14:24:57 -0800123 }
124 }
Andres Morales5ca4cc52015-03-19 16:37:54 -0700125
126 SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
Andres Morales1ce7d172015-01-07 14:24:57 -0800127 }
128
Amith Yamasanid2b21042016-06-03 10:12:47 -0700129 private void enforceOemUnlockReadPermission() {
130 if (mContext.checkCallingOrSelfPermission(Manifest.permission.READ_OEM_UNLOCK_STATE)
131 == PackageManager.PERMISSION_DENIED
132 && mContext.checkCallingOrSelfPermission(Manifest.permission.OEM_UNLOCK_STATE)
133 == PackageManager.PERMISSION_DENIED) {
134 throw new SecurityException("Can't access OEM unlock state. Requires "
135 + "READ_OEM_UNLOCK_STATE or OEM_UNLOCK_STATE permission.");
136 }
137 }
138
139 private void enforceOemUnlockWritePermission() {
Andres Morales68d4acd2014-07-01 19:40:41 -0700140 mContext.enforceCallingOrSelfPermission(
141 Manifest.permission.OEM_UNLOCK_STATE,
Amith Yamasanid2b21042016-06-03 10:12:47 -0700142 "Can't modify OEM unlock state");
Andres Morales68d4acd2014-07-01 19:40:41 -0700143 }
144
145 private void enforceUid(int callingUid) {
Andres Moralesa31c23d2014-10-30 15:31:31 -0700146 if (callingUid != mAllowedUid) {
Andres Morales68d4acd2014-07-01 19:40:41 -0700147 throw new SecurityException("uid " + callingUid + " not allowed to access PST");
148 }
149 }
150
Xiaohui Chenf0660782015-09-02 14:25:19 -0700151 private void enforceIsAdmin() {
152 final int userId = UserHandle.getCallingUserId();
153 final boolean isAdmin = UserManager.get(mContext).isUserAdmin(userId);
154 if (!isAdmin) {
155 throw new SecurityException(
156 "Only the Admin user is allowed to change OEM unlock state");
Andres Moralesa31c23d2014-10-30 15:31:31 -0700157 }
158 }
Mahaver Chopra830e32c2016-05-17 18:53:09 +0100159
Mahaver Chopra3d9805d2016-07-07 16:25:05 +0100160 private void enforceUserRestriction(String userRestriction) {
161 if (UserManager.get(mContext).hasUserRestriction(userRestriction)) {
162 throw new SecurityException(
163 "OEM unlock is disallowed by user restriction: " + userRestriction);
Mahaver Chopra830e32c2016-05-17 18:53:09 +0100164 }
165 }
166
Andres Morales963295e2014-07-10 15:40:24 -0700167 private int getTotalDataSizeLocked(DataInputStream inputStream) throws IOException {
Andres Morales28301302014-11-12 07:56:46 -0800168 // skip over checksum
169 inputStream.skipBytes(DIGEST_SIZE_BYTES);
170
Andres Morales68d4acd2014-07-01 19:40:41 -0700171 int totalDataSize;
172 int blockId = inputStream.readInt();
Andres Morales963295e2014-07-10 15:40:24 -0700173 if (blockId == PARTITION_TYPE_MARKER) {
Andres Morales68d4acd2014-07-01 19:40:41 -0700174 totalDataSize = inputStream.readInt();
175 } else {
176 totalDataSize = 0;
177 }
178 return totalDataSize;
179 }
180
Andres Morales963295e2014-07-10 15:40:24 -0700181 private long getBlockDeviceSize() {
182 synchronized (mLock) {
183 if (mBlockDeviceSize == -1) {
184 mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
Andres Morales68d4acd2014-07-01 19:40:41 -0700185 }
186 }
187
188 return mBlockDeviceSize;
189 }
190
Andres Morales28301302014-11-12 07:56:46 -0800191 private boolean enforceChecksumValidity() {
192 byte[] storedDigest = new byte[DIGEST_SIZE_BYTES];
193
194 synchronized (mLock) {
195 byte[] digest = computeDigestLocked(storedDigest);
196 if (digest == null || !Arrays.equals(storedDigest, digest)) {
197 Slog.i(TAG, "Formatting FRP partition...");
Andres Moralesc8f952c2015-03-19 08:34:55 -0700198 formatPartitionLocked(false);
Andres Morales28301302014-11-12 07:56:46 -0800199 return false;
200 }
201 }
202
203 return true;
204 }
205
206 private boolean computeAndWriteDigestLocked() {
207 byte[] digest = computeDigestLocked(null);
208 if (digest != null) {
209 DataOutputStream outputStream;
210 try {
211 outputStream = new DataOutputStream(
212 new FileOutputStream(new File(mDataBlockFile)));
213 } catch (FileNotFoundException e) {
214 Slog.e(TAG, "partition not available?", e);
215 return false;
216 }
217
218 try {
219 outputStream.write(digest, 0, DIGEST_SIZE_BYTES);
220 outputStream.flush();
221 } catch (IOException e) {
222 Slog.e(TAG, "failed to write block checksum", e);
223 return false;
224 } finally {
225 IoUtils.closeQuietly(outputStream);
226 }
227 return true;
228 } else {
229 return false;
230 }
231 }
232
233 private byte[] computeDigestLocked(byte[] storedDigest) {
234 DataInputStream inputStream;
235 try {
236 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
237 } catch (FileNotFoundException e) {
238 Slog.e(TAG, "partition not available?", e);
239 return null;
240 }
241
242 MessageDigest md;
243 try {
244 md = MessageDigest.getInstance("SHA-256");
245 } catch (NoSuchAlgorithmException e) {
246 // won't ever happen -- every implementation is required to support SHA-256
247 Slog.e(TAG, "SHA-256 not supported?", e);
248 IoUtils.closeQuietly(inputStream);
249 return null;
250 }
251
252 try {
253 if (storedDigest != null && storedDigest.length == DIGEST_SIZE_BYTES) {
254 inputStream.read(storedDigest);
255 } else {
256 inputStream.skipBytes(DIGEST_SIZE_BYTES);
257 }
258
259 int read;
260 byte[] data = new byte[1024];
261 md.update(data, 0, DIGEST_SIZE_BYTES); // include 0 checksum in digest
262 while ((read = inputStream.read(data)) != -1) {
263 md.update(data, 0, read);
264 }
265 } catch (IOException e) {
266 Slog.e(TAG, "failed to read partition", e);
267 return null;
268 } finally {
269 IoUtils.closeQuietly(inputStream);
270 }
271
272 return md.digest();
273 }
274
Andres Moralesc8f952c2015-03-19 08:34:55 -0700275 private void formatPartitionLocked(boolean setOemUnlockEnabled) {
Andres Morales28301302014-11-12 07:56:46 -0800276 DataOutputStream outputStream;
277 try {
278 outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
279 } catch (FileNotFoundException e) {
280 Slog.e(TAG, "partition not available?", e);
281 return;
282 }
283
284 byte[] data = new byte[DIGEST_SIZE_BYTES];
285 try {
286 outputStream.write(data, 0, DIGEST_SIZE_BYTES);
287 outputStream.writeInt(PARTITION_TYPE_MARKER);
288 outputStream.writeInt(0); // data size
289 outputStream.flush();
290 } catch (IOException e) {
291 Slog.e(TAG, "failed to format block", e);
292 return;
293 } finally {
294 IoUtils.closeQuietly(outputStream);
295 }
296
Andres Moralesc8f952c2015-03-19 08:34:55 -0700297 doSetOemUnlockEnabledLocked(setOemUnlockEnabled);
Andres Morales28301302014-11-12 07:56:46 -0800298 computeAndWriteDigestLocked();
299 }
300
301 private void doSetOemUnlockEnabledLocked(boolean enabled) {
302 FileOutputStream outputStream;
303 try {
304 outputStream = new FileOutputStream(new File(mDataBlockFile));
305 } catch (FileNotFoundException e) {
306 Slog.e(TAG, "partition not available", e);
307 return;
308 }
309
310 try {
311 FileChannel channel = outputStream.getChannel();
312
313 channel.position(getBlockDeviceSize() - 1);
314
315 ByteBuffer data = ByteBuffer.allocate(1);
316 data.put(enabled ? (byte) 1 : (byte) 0);
317 data.flip();
318 channel.write(data);
319 outputStream.flush();
320 } catch (IOException e) {
321 Slog.e(TAG, "unable to access persistent partition", e);
322 return;
323 } finally {
Andres Morales5ca4cc52015-03-19 16:37:54 -0700324 SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
Andres Morales28301302014-11-12 07:56:46 -0800325 IoUtils.closeQuietly(outputStream);
326 }
327 }
328
Andres Morales1ce7d172015-01-07 14:24:57 -0800329 private boolean doGetOemUnlockEnabled() {
330 DataInputStream inputStream;
331 try {
332 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
333 } catch (FileNotFoundException e) {
334 Slog.e(TAG, "partition not available");
335 return false;
336 }
337
338 try {
339 synchronized (mLock) {
340 inputStream.skip(getBlockDeviceSize() - 1);
341 return inputStream.readByte() != 0;
342 }
343 } catch (IOException e) {
344 Slog.e(TAG, "unable to access persistent partition", e);
345 return false;
346 } finally {
347 IoUtils.closeQuietly(inputStream);
348 }
349 }
350
Andres Morales963295e2014-07-10 15:40:24 -0700351 private native long nativeGetBlockDeviceSize(String path);
352 private native int nativeWipe(String path);
Andres Morales68d4acd2014-07-01 19:40:41 -0700353
354 private final IBinder mService = new IPersistentDataBlockService.Stub() {
355 @Override
356 public int write(byte[] data) throws RemoteException {
357 enforceUid(Binder.getCallingUid());
358
359 // Need to ensure we don't write over the last byte
Andres Morales963295e2014-07-10 15:40:24 -0700360 long maxBlockSize = getBlockDeviceSize() - HEADER_SIZE - 1;
361 if (data.length > maxBlockSize) {
362 // partition is ~500k so shouldn't be a problem to downcast
363 return (int) -maxBlockSize;
Andres Morales68d4acd2014-07-01 19:40:41 -0700364 }
365
366 DataOutputStream outputStream;
367 try {
368 outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
369 } catch (FileNotFoundException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700370 Slog.e(TAG, "partition not available?", e);
Andres Morales68d4acd2014-07-01 19:40:41 -0700371 return -1;
372 }
373
374 ByteBuffer headerAndData = ByteBuffer.allocate(data.length + HEADER_SIZE);
Andres Morales963295e2014-07-10 15:40:24 -0700375 headerAndData.putInt(PARTITION_TYPE_MARKER);
Andres Morales68d4acd2014-07-01 19:40:41 -0700376 headerAndData.putInt(data.length);
377 headerAndData.put(data);
378
Andres Morales28301302014-11-12 07:56:46 -0800379 synchronized (mLock) {
Andres Morales68d4acd2014-07-01 19:40:41 -0700380 try {
Andres Morales28301302014-11-12 07:56:46 -0800381 byte[] checksum = new byte[DIGEST_SIZE_BYTES];
382 outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
383 outputStream.write(headerAndData.array());
384 outputStream.flush();
Andres Morales68d4acd2014-07-01 19:40:41 -0700385 } catch (IOException e) {
Andres Morales28301302014-11-12 07:56:46 -0800386 Slog.e(TAG, "failed writing to the persistent data block", e);
387 return -1;
388 } finally {
389 IoUtils.closeQuietly(outputStream);
390 }
391
392 if (computeAndWriteDigestLocked()) {
393 return data.length;
394 } else {
395 return -1;
Andres Morales68d4acd2014-07-01 19:40:41 -0700396 }
397 }
398 }
399
400 @Override
Andres Morales963295e2014-07-10 15:40:24 -0700401 public byte[] read() {
Andres Morales68d4acd2014-07-01 19:40:41 -0700402 enforceUid(Binder.getCallingUid());
Andres Morales28301302014-11-12 07:56:46 -0800403 if (!enforceChecksumValidity()) {
404 return new byte[0];
405 }
Andres Morales68d4acd2014-07-01 19:40:41 -0700406
407 DataInputStream inputStream;
408 try {
409 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
410 } catch (FileNotFoundException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700411 Slog.e(TAG, "partition not available?", e);
412 return null;
Andres Morales68d4acd2014-07-01 19:40:41 -0700413 }
414
415 try {
Andres Morales963295e2014-07-10 15:40:24 -0700416 synchronized (mLock) {
417 int totalDataSize = getTotalDataSizeLocked(inputStream);
418
419 if (totalDataSize == 0) {
420 return new byte[0];
421 }
422
423 byte[] data = new byte[totalDataSize];
424 int read = inputStream.read(data, 0, totalDataSize);
425 if (read < totalDataSize) {
426 // something went wrong, not returning potentially corrupt data
427 Slog.e(TAG, "failed to read entire data block. bytes read: " +
428 read + "/" + totalDataSize);
429 return null;
430 }
431 return data;
432 }
Andres Morales68d4acd2014-07-01 19:40:41 -0700433 } catch (IOException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700434 Slog.e(TAG, "failed to read data", e);
435 return null;
Andres Morales68d4acd2014-07-01 19:40:41 -0700436 } finally {
437 try {
438 inputStream.close();
439 } catch (IOException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700440 Slog.e(TAG, "failed to close OutputStream");
441 }
442 }
443 }
444
445 @Override
446 public void wipe() {
Amith Yamasanid2b21042016-06-03 10:12:47 -0700447 enforceOemUnlockWritePermission();
Andres Morales963295e2014-07-10 15:40:24 -0700448
449 synchronized (mLock) {
450 int ret = nativeWipe(mDataBlockFile);
451
452 if (ret < 0) {
453 Slog.e(TAG, "failed to wipe persistent partition");
Andres Morales68d4acd2014-07-01 19:40:41 -0700454 }
455 }
456 }
457
458 @Override
Steven Ngdc20ba62016-04-26 18:19:04 +0100459 public void setOemUnlockEnabled(boolean enabled) throws SecurityException {
Guang Zhu514c5802014-09-12 15:14:00 -0700460 // do not allow monkey to flip the flag
461 if (ActivityManager.isUserAMonkey()) {
462 return;
463 }
Steven Ngbfe1b042016-05-16 11:20:57 +0100464
Amith Yamasanid2b21042016-06-03 10:12:47 -0700465 enforceOemUnlockWritePermission();
Steven Ngbfe1b042016-05-16 11:20:57 +0100466 enforceIsAdmin();
467
Mahaver Chopra830e32c2016-05-17 18:53:09 +0100468 if (enabled) {
Mahaver Chopra3d9805d2016-07-07 16:25:05 +0100469 // Do not allow oem unlock to be enabled if it's disallowed by a user restriction.
470 enforceUserRestriction(UserManager.DISALLOW_OEM_UNLOCK);
471 enforceUserRestriction(UserManager.DISALLOW_FACTORY_RESET);
Mahaver Chopra830e32c2016-05-17 18:53:09 +0100472 }
Andres Morales28301302014-11-12 07:56:46 -0800473 synchronized (mLock) {
474 doSetOemUnlockEnabledLocked(enabled);
475 computeAndWriteDigestLocked();
Andres Morales68d4acd2014-07-01 19:40:41 -0700476 }
477 }
478
479 @Override
480 public boolean getOemUnlockEnabled() {
Amith Yamasanid2b21042016-06-03 10:12:47 -0700481 enforceOemUnlockReadPermission();
Andres Morales1ce7d172015-01-07 14:24:57 -0800482 return doGetOemUnlockEnabled();
Andres Morales68d4acd2014-07-01 19:40:41 -0700483 }
484
485 @Override
Andres Morales74e9b182016-02-22 12:33:33 -0800486 public int getFlashLockState() {
Amith Yamasanid2b21042016-06-03 10:12:47 -0700487 enforceOemUnlockReadPermission();
Andres Morales74e9b182016-02-22 12:33:33 -0800488 String locked = SystemProperties.get(FLASH_LOCK_PROP);
489 switch (locked) {
490 case FLASH_LOCK_LOCKED:
491 return PersistentDataBlockManager.FLASH_LOCK_LOCKED;
492 case FLASH_LOCK_UNLOCKED:
493 return PersistentDataBlockManager.FLASH_LOCK_UNLOCKED;
494 default:
495 return PersistentDataBlockManager.FLASH_LOCK_UNKNOWN;
496 }
497 }
498
499 @Override
Andres Morales68d4acd2014-07-01 19:40:41 -0700500 public int getDataBlockSize() {
Craig Lafayette66445a62015-03-27 09:01:43 -0400501 enforcePersistentDataBlockAccess();
Andres Morales68d4acd2014-07-01 19:40:41 -0700502
503 DataInputStream inputStream;
504 try {
505 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
506 } catch (FileNotFoundException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700507 Slog.e(TAG, "partition not available");
Andres Morales68d4acd2014-07-01 19:40:41 -0700508 return 0;
509 }
510
511 try {
Andres Morales963295e2014-07-10 15:40:24 -0700512 synchronized (mLock) {
513 return getTotalDataSizeLocked(inputStream);
514 }
Andres Morales68d4acd2014-07-01 19:40:41 -0700515 } catch (IOException e) {
Andres Morales963295e2014-07-10 15:40:24 -0700516 Slog.e(TAG, "error reading data block size");
Andres Morales68d4acd2014-07-01 19:40:41 -0700517 return 0;
518 } finally {
Andres Morales963295e2014-07-10 15:40:24 -0700519 IoUtils.closeQuietly(inputStream);
Andres Morales68d4acd2014-07-01 19:40:41 -0700520 }
521 }
Andres Morales963295e2014-07-10 15:40:24 -0700522
Craig Lafayette66445a62015-03-27 09:01:43 -0400523 private void enforcePersistentDataBlockAccess() {
524 if (mContext.checkCallingPermission(Manifest.permission.ACCESS_PDB_STATE)
525 != PackageManager.PERMISSION_GRANTED) {
526 enforceUid(Binder.getCallingUid());
527 }
528 }
529
Andres Morales963295e2014-07-10 15:40:24 -0700530 @Override
531 public long getMaximumDataBlockSize() {
532 long actualSize = getBlockDeviceSize() - HEADER_SIZE - 1;
533 return actualSize <= MAX_DATA_BLOCK_SIZE ? actualSize : MAX_DATA_BLOCK_SIZE;
534 }
Andres Morales68d4acd2014-07-01 19:40:41 -0700535 };
536}