1 /* 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 17 package com.android.server; 18 19 import static com.android.internal.util.Preconditions.checkArgument; 20 21 import android.Manifest; 22 import android.app.ActivityManager; 23 import android.content.Context; 24 import android.content.pm.PackageManager; 25 import android.os.Binder; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.os.SystemProperties; 29 import android.os.UserHandle; 30 import android.os.UserManager; 31 import android.service.persistentdata.IPersistentDataBlockService; 32 import android.service.persistentdata.PersistentDataBlockManager; 33 import android.text.TextUtils; 34 import android.util.Slog; 35 36 import com.android.internal.R; 37 import com.android.internal.annotations.GuardedBy; 38 import com.android.internal.util.DumpUtils; 39 import com.android.server.pm.UserManagerInternal; 40 41 import libcore.io.IoUtils; 42 43 import java.io.DataInputStream; 44 import java.io.File; 45 import java.io.FileDescriptor; 46 import java.io.FileInputStream; 47 import java.io.FileNotFoundException; 48 import java.io.IOException; 49 import java.io.PrintWriter; 50 import java.io.RandomAccessFile; 51 import java.nio.ByteBuffer; 52 import java.nio.channels.FileChannel; 53 import java.security.MessageDigest; 54 import java.security.NoSuchAlgorithmException; 55 import java.util.Arrays; 56 import java.util.concurrent.CountDownLatch; 57 import java.util.concurrent.TimeUnit; 58 59 /** 60 * Service for reading and writing blocks to a persistent partition. 61 * This data will live across factory resets not initiated via the Settings UI. 62 * When a device is factory reset through Settings this data is wiped. 63 * 64 * Allows writing one block at a time. Namely, each time {@link IPersistentDataBlockService#write} 65 * is called, it will overwrite the data that was previously written on the block. 66 * 67 * Clients can query the size of the currently written block via 68 * {@link IPersistentDataBlockService#getDataBlockSize} 69 * 70 * Clients can read any number of bytes from the currently written block up to its total size by 71 * invoking {@link IPersistentDataBlockService#read} 72 * 73 * The persistent data block is currently laid out as follows: 74 * | ---------BEGINNING OF PARTITION-------------| 75 * | Partition digest (32 bytes) | 76 * | --------------------------------------------| 77 * | PARTITION_TYPE_MARKER (4 bytes) | 78 * | --------------------------------------------| 79 * | FRP data block length (4 bytes) | 80 * | --------------------------------------------| 81 * | FRP data (variable length) | 82 * | --------------------------------------------| 83 * | ... | 84 * | --------------------------------------------| 85 * | Test mode data block (10000 bytes) | 86 * | --------------------------------------------| 87 * | | Test mode data length (4 bytes) | 88 * | --------------------------------------------| 89 * | | Test mode data (variable length) | 90 * | | ... | 91 * | --------------------------------------------| 92 * | FRP credential handle block (1000 bytes) | 93 * | --------------------------------------------| 94 * | | FRP credential handle length (4 bytes)| 95 * | --------------------------------------------| 96 * | | FRP credential handle (variable len) | 97 * | | ... | 98 * | --------------------------------------------| 99 * | OEM Unlock bit (1 byte) | 100 * | ---------END OF PARTITION-------------------| 101 * 102 * TODO: now that the persistent partition contains several blocks, next time someone wants a new 103 * block, we should look at adding more generic block definitions and get rid of the various raw 104 * XXX_RESERVED_SIZE and XXX_DATA_SIZE constants. That will ensure the code is easier to maintain 105 * and less likely to introduce out-of-bounds read/write. 106 */ 107 public class PersistentDataBlockService extends SystemService { 108 private static final String TAG = PersistentDataBlockService.class.getSimpleName(); 109 110 private static final String GSI_SANDBOX = "/data/gsi_persistent_data"; 111 private static final String GSI_RUNNING_PROP = "ro.gsid.image_running"; 112 113 private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst"; 114 private static final int HEADER_SIZE = 8; 115 // Magic number to mark block device as adhering to the format consumed by this service 116 private static final int PARTITION_TYPE_MARKER = 0x19901873; 117 /** Size of the block reserved for FRP credential, including 4 bytes for the size header. */ 118 private static final int FRP_CREDENTIAL_RESERVED_SIZE = 1000; 119 /** Maximum size of the FRP credential handle that can be stored. */ 120 private static final int MAX_FRP_CREDENTIAL_HANDLE_SIZE = FRP_CREDENTIAL_RESERVED_SIZE - 4; 121 /** 122 * Size of the block reserved for Test Harness Mode data, including 4 bytes for the size header. 123 */ 124 private static final int TEST_MODE_RESERVED_SIZE = 10000; 125 /** Maximum size of the Test Harness Mode data that can be stored. */ 126 private static final int MAX_TEST_MODE_DATA_SIZE = TEST_MODE_RESERVED_SIZE - 4; 127 // Limit to 100k as blocks larger than this might cause strain on Binder. 128 private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100; 129 130 public static final int DIGEST_SIZE_BYTES = 32; 131 private static final String OEM_UNLOCK_PROP = "sys.oem_unlock_allowed"; 132 private static final String FLASH_LOCK_PROP = "ro.boot.flash.locked"; 133 private static final String FLASH_LOCK_LOCKED = "1"; 134 private static final String FLASH_LOCK_UNLOCKED = "0"; 135 136 private final Context mContext; 137 private final String mDataBlockFile; 138 private final boolean mIsRunningDSU; 139 private final Object mLock = new Object(); 140 private final CountDownLatch mInitDoneSignal = new CountDownLatch(1); 141 142 private int mAllowedUid = -1; 143 private long mBlockDeviceSize; 144 145 @GuardedBy("mLock") 146 private boolean mIsWritable = true; 147 PersistentDataBlockService(Context context)148 public PersistentDataBlockService(Context context) { 149 super(context); 150 mContext = context; 151 mIsRunningDSU = SystemProperties.getBoolean(GSI_RUNNING_PROP, false); 152 if (mIsRunningDSU) { 153 mDataBlockFile = GSI_SANDBOX; 154 } else { 155 mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP); 156 } 157 mBlockDeviceSize = -1; // Load lazily 158 } 159 getAllowedUid()160 private int getAllowedUid() { 161 final UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class); 162 int mainUserId = umInternal.getMainUserId(); 163 if (mainUserId < 0) { 164 // If main user is not defined. Use the SYSTEM user instead. 165 mainUserId = UserHandle.USER_SYSTEM; 166 } 167 String allowedPackage = mContext.getResources() 168 .getString(R.string.config_persistentDataPackageName); 169 int allowedUid = -1; 170 if (!TextUtils.isEmpty(allowedPackage)) { 171 try { 172 allowedUid = mContext.getPackageManager().getPackageUidAsUser( 173 allowedPackage, PackageManager.MATCH_SYSTEM_ONLY, mainUserId); 174 } catch (PackageManager.NameNotFoundException e) { 175 // not expected 176 Slog.e(TAG, "not able to find package " + allowedPackage, e); 177 } 178 } 179 return allowedUid; 180 } 181 182 @Override onStart()183 public void onStart() { 184 // Do init on a separate thread, will join in PHASE_ACTIVITY_MANAGER_READY 185 SystemServerInitThreadPool.submit(() -> { 186 enforceChecksumValidity(); 187 formatIfOemUnlockEnabled(); 188 publishBinderService(Context.PERSISTENT_DATA_BLOCK_SERVICE, mService); 189 mInitDoneSignal.countDown(); 190 }, TAG + ".onStart"); 191 } 192 193 @Override onBootPhase(int phase)194 public void onBootPhase(int phase) { 195 // Wait for initialization in onStart to finish 196 if (phase == PHASE_SYSTEM_SERVICES_READY) { 197 try { 198 if (!mInitDoneSignal.await(10, TimeUnit.SECONDS)) { 199 throw new IllegalStateException("Service " + TAG + " init timeout"); 200 } 201 } catch (InterruptedException e) { 202 Thread.currentThread().interrupt(); 203 throw new IllegalStateException("Service " + TAG + " init interrupted", e); 204 } 205 // The user responsible for FRP should exist by now. 206 mAllowedUid = getAllowedUid(); 207 LocalServices.addService(PersistentDataBlockManagerInternal.class, mInternalService); 208 } 209 super.onBootPhase(phase); 210 } 211 formatIfOemUnlockEnabled()212 private void formatIfOemUnlockEnabled() { 213 boolean enabled = doGetOemUnlockEnabled(); 214 if (enabled) { 215 synchronized (mLock) { 216 formatPartitionLocked(true); 217 } 218 } 219 220 SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0"); 221 } 222 enforceOemUnlockReadPermission()223 private void enforceOemUnlockReadPermission() { 224 if (mContext.checkCallingOrSelfPermission(Manifest.permission.READ_OEM_UNLOCK_STATE) 225 == PackageManager.PERMISSION_DENIED 226 && mContext.checkCallingOrSelfPermission(Manifest.permission.OEM_UNLOCK_STATE) 227 == PackageManager.PERMISSION_DENIED) { 228 throw new SecurityException("Can't access OEM unlock state. Requires " 229 + "READ_OEM_UNLOCK_STATE or OEM_UNLOCK_STATE permission."); 230 } 231 } 232 enforceOemUnlockWritePermission()233 private void enforceOemUnlockWritePermission() { 234 mContext.enforceCallingOrSelfPermission( 235 Manifest.permission.OEM_UNLOCK_STATE, 236 "Can't modify OEM unlock state"); 237 } 238 enforceUid(int callingUid)239 private void enforceUid(int callingUid) { 240 if (callingUid != mAllowedUid) { 241 throw new SecurityException("uid " + callingUid + " not allowed to access PST"); 242 } 243 } 244 enforceIsAdmin()245 private void enforceIsAdmin() { 246 final int userId = UserHandle.getCallingUserId(); 247 final boolean isAdmin = UserManager.get(mContext).isUserAdmin(userId); 248 if (!isAdmin) { 249 throw new SecurityException( 250 "Only the Admin user is allowed to change OEM unlock state"); 251 } 252 } 253 enforceUserRestriction(String userRestriction)254 private void enforceUserRestriction(String userRestriction) { 255 if (UserManager.get(mContext).hasUserRestriction(userRestriction)) { 256 throw new SecurityException( 257 "OEM unlock is disallowed by user restriction: " + userRestriction); 258 } 259 } 260 getTotalDataSizeLocked(DataInputStream inputStream)261 private int getTotalDataSizeLocked(DataInputStream inputStream) throws IOException { 262 // skip over checksum 263 inputStream.skipBytes(DIGEST_SIZE_BYTES); 264 265 int totalDataSize; 266 int blockId = inputStream.readInt(); 267 if (blockId == PARTITION_TYPE_MARKER) { 268 totalDataSize = inputStream.readInt(); 269 } else { 270 totalDataSize = 0; 271 } 272 return totalDataSize; 273 } 274 getBlockDeviceSize()275 private long getBlockDeviceSize() { 276 synchronized (mLock) { 277 if (mBlockDeviceSize == -1) { 278 if (mIsRunningDSU) { 279 mBlockDeviceSize = MAX_DATA_BLOCK_SIZE; 280 } else { 281 mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile); 282 } 283 } 284 } 285 286 return mBlockDeviceSize; 287 } 288 getFrpCredentialDataOffset()289 private long getFrpCredentialDataOffset() { 290 return getBlockDeviceSize() - 1 - FRP_CREDENTIAL_RESERVED_SIZE; 291 } 292 getTestHarnessModeDataOffset()293 private long getTestHarnessModeDataOffset() { 294 return getFrpCredentialDataOffset() - TEST_MODE_RESERVED_SIZE; 295 } 296 enforceChecksumValidity()297 private boolean enforceChecksumValidity() { 298 byte[] storedDigest = new byte[DIGEST_SIZE_BYTES]; 299 300 synchronized (mLock) { 301 byte[] digest = computeDigestLocked(storedDigest); 302 if (digest == null || !Arrays.equals(storedDigest, digest)) { 303 Slog.i(TAG, "Formatting FRP partition..."); 304 formatPartitionLocked(false); 305 return false; 306 } 307 } 308 309 return true; 310 } 311 getBlockOutputChannel()312 private FileChannel getBlockOutputChannel() throws IOException { 313 return new RandomAccessFile(mDataBlockFile, "rw").getChannel(); 314 } 315 computeAndWriteDigestLocked()316 private boolean computeAndWriteDigestLocked() { 317 byte[] digest = computeDigestLocked(null); 318 if (digest != null) { 319 FileChannel channel; 320 try { 321 channel = getBlockOutputChannel(); 322 } catch (IOException e) { 323 Slog.e(TAG, "partition not available?", e); 324 return false; 325 } 326 327 try { 328 ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES); 329 buf.put(digest); 330 buf.flip(); 331 channel.write(buf); 332 channel.force(true); 333 } catch (IOException e) { 334 Slog.e(TAG, "failed to write block checksum", e); 335 return false; 336 } 337 return true; 338 } else { 339 return false; 340 } 341 } 342 computeDigestLocked(byte[] storedDigest)343 private byte[] computeDigestLocked(byte[] storedDigest) { 344 DataInputStream inputStream; 345 try { 346 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile))); 347 } catch (FileNotFoundException e) { 348 Slog.e(TAG, "partition not available?", e); 349 return null; 350 } 351 352 MessageDigest md; 353 try { 354 md = MessageDigest.getInstance("SHA-256"); 355 } catch (NoSuchAlgorithmException e) { 356 // won't ever happen -- every implementation is required to support SHA-256 357 Slog.e(TAG, "SHA-256 not supported?", e); 358 IoUtils.closeQuietly(inputStream); 359 return null; 360 } 361 362 try { 363 if (storedDigest != null && storedDigest.length == DIGEST_SIZE_BYTES) { 364 inputStream.read(storedDigest); 365 } else { 366 inputStream.skipBytes(DIGEST_SIZE_BYTES); 367 } 368 369 int read; 370 byte[] data = new byte[1024]; 371 md.update(data, 0, DIGEST_SIZE_BYTES); // include 0 checksum in digest 372 while ((read = inputStream.read(data)) != -1) { 373 md.update(data, 0, read); 374 } 375 } catch (IOException e) { 376 Slog.e(TAG, "failed to read partition", e); 377 return null; 378 } finally { 379 IoUtils.closeQuietly(inputStream); 380 } 381 382 return md.digest(); 383 } 384 formatPartitionLocked(boolean setOemUnlockEnabled)385 private void formatPartitionLocked(boolean setOemUnlockEnabled) { 386 387 try { 388 FileChannel channel = getBlockOutputChannel(); 389 // Format the data selectively. 390 // 391 // 1. write header, set length = 0 392 int header_size = DIGEST_SIZE_BYTES + HEADER_SIZE; 393 ByteBuffer buf = ByteBuffer.allocate(header_size); 394 buf.put(new byte[DIGEST_SIZE_BYTES]); 395 buf.putInt(PARTITION_TYPE_MARKER); 396 buf.putInt(0); 397 buf.flip(); 398 channel.write(buf); 399 channel.force(true); 400 401 // 2. corrupt the legacy FRP data explicitly 402 int payload_size = (int) getBlockDeviceSize() - header_size; 403 buf = ByteBuffer.allocate(payload_size 404 - TEST_MODE_RESERVED_SIZE - FRP_CREDENTIAL_RESERVED_SIZE - 1); 405 channel.write(buf); 406 channel.force(true); 407 408 // 3. skip the test mode data and leave it unformat 409 // This is for a feature that enables testing. 410 channel.position(channel.position() + TEST_MODE_RESERVED_SIZE); 411 412 // 4. wipe the FRP_CREDENTIAL explicitly 413 buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE); 414 channel.write(buf); 415 channel.force(true); 416 417 // 5. set unlock = 0 because it's a formatPartitionLocked 418 buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE); 419 buf.put((byte)0); 420 buf.flip(); 421 channel.write(buf); 422 channel.force(true); 423 } catch (IOException e) { 424 Slog.e(TAG, "failed to format block", e); 425 return; 426 } 427 428 doSetOemUnlockEnabledLocked(setOemUnlockEnabled); 429 computeAndWriteDigestLocked(); 430 } 431 doSetOemUnlockEnabledLocked(boolean enabled)432 private void doSetOemUnlockEnabledLocked(boolean enabled) { 433 434 try { 435 FileChannel channel = getBlockOutputChannel(); 436 437 channel.position(getBlockDeviceSize() - 1); 438 439 ByteBuffer data = ByteBuffer.allocate(1); 440 data.put(enabled ? (byte) 1 : (byte) 0); 441 data.flip(); 442 channel.write(data); 443 channel.force(true); 444 } catch (IOException e) { 445 Slog.e(TAG, "unable to access persistent partition", e); 446 return; 447 } finally { 448 SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0"); 449 } 450 } 451 doGetOemUnlockEnabled()452 private boolean doGetOemUnlockEnabled() { 453 DataInputStream inputStream; 454 try { 455 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile))); 456 } catch (FileNotFoundException e) { 457 Slog.e(TAG, "partition not available"); 458 return false; 459 } 460 461 try { 462 synchronized (mLock) { 463 inputStream.skip(getBlockDeviceSize() - 1); 464 return inputStream.readByte() != 0; 465 } 466 } catch (IOException e) { 467 Slog.e(TAG, "unable to access persistent partition", e); 468 return false; 469 } finally { 470 IoUtils.closeQuietly(inputStream); 471 } 472 } 473 doGetMaximumDataBlockSize()474 private long doGetMaximumDataBlockSize() { 475 long actualSize = getBlockDeviceSize() - HEADER_SIZE - DIGEST_SIZE_BYTES 476 - TEST_MODE_RESERVED_SIZE - FRP_CREDENTIAL_RESERVED_SIZE - 1; 477 return actualSize <= MAX_DATA_BLOCK_SIZE ? actualSize : MAX_DATA_BLOCK_SIZE; 478 } 479 nativeGetBlockDeviceSize(String path)480 private native long nativeGetBlockDeviceSize(String path); nativeWipe(String path)481 private native int nativeWipe(String path); 482 483 private final IBinder mService = new IPersistentDataBlockService.Stub() { 484 485 /** 486 * Write the data to the persistent data block. 487 * 488 * @return a positive integer of the number of bytes that were written if successful, 489 * otherwise a negative integer indicating there was a problem 490 */ 491 @Override 492 public int write(byte[] data) throws RemoteException { 493 enforceUid(Binder.getCallingUid()); 494 495 // Need to ensure we don't write over the last byte 496 long maxBlockSize = doGetMaximumDataBlockSize(); 497 if (data.length > maxBlockSize) { 498 // partition is ~500k so shouldn't be a problem to downcast 499 return (int) -maxBlockSize; 500 } 501 502 FileChannel channel; 503 try { 504 channel = getBlockOutputChannel(); 505 } catch (IOException e) { 506 Slog.e(TAG, "partition not available?", e); 507 return -1; 508 } 509 510 ByteBuffer headerAndData = ByteBuffer.allocate( 511 data.length + HEADER_SIZE + DIGEST_SIZE_BYTES); 512 headerAndData.put(new byte[DIGEST_SIZE_BYTES]); 513 headerAndData.putInt(PARTITION_TYPE_MARKER); 514 headerAndData.putInt(data.length); 515 headerAndData.put(data); 516 headerAndData.flip(); 517 synchronized (mLock) { 518 if (!mIsWritable) { 519 return -1; 520 } 521 522 try { 523 channel.write(headerAndData); 524 channel.force(true); 525 } catch (IOException e) { 526 Slog.e(TAG, "failed writing to the persistent data block", e); 527 return -1; 528 } 529 530 if (computeAndWriteDigestLocked()) { 531 return data.length; 532 } else { 533 return -1; 534 } 535 } 536 } 537 538 @Override 539 public byte[] read() { 540 enforceUid(Binder.getCallingUid()); 541 if (!enforceChecksumValidity()) { 542 return new byte[0]; 543 } 544 545 DataInputStream inputStream; 546 try { 547 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile))); 548 } catch (FileNotFoundException e) { 549 Slog.e(TAG, "partition not available?", e); 550 return null; 551 } 552 553 try { 554 synchronized (mLock) { 555 int totalDataSize = getTotalDataSizeLocked(inputStream); 556 557 if (totalDataSize == 0) { 558 return new byte[0]; 559 } 560 561 byte[] data = new byte[totalDataSize]; 562 int read = inputStream.read(data, 0, totalDataSize); 563 if (read < totalDataSize) { 564 // something went wrong, not returning potentially corrupt data 565 Slog.e(TAG, "failed to read entire data block. bytes read: " + 566 read + "/" + totalDataSize); 567 return null; 568 } 569 return data; 570 } 571 } catch (IOException e) { 572 Slog.e(TAG, "failed to read data", e); 573 return null; 574 } finally { 575 try { 576 inputStream.close(); 577 } catch (IOException e) { 578 Slog.e(TAG, "failed to close OutputStream"); 579 } 580 } 581 } 582 583 @Override 584 public void wipe() { 585 enforceOemUnlockWritePermission(); 586 587 synchronized (mLock) { 588 int ret = nativeWipe(mDataBlockFile); 589 590 if (ret < 0) { 591 Slog.e(TAG, "failed to wipe persistent partition"); 592 } else { 593 mIsWritable = false; 594 Slog.i(TAG, "persistent partition now wiped and unwritable"); 595 } 596 } 597 } 598 599 @Override 600 public void setOemUnlockEnabled(boolean enabled) throws SecurityException { 601 // do not allow monkey to flip the flag 602 if (ActivityManager.isUserAMonkey()) { 603 return; 604 } 605 606 enforceOemUnlockWritePermission(); 607 enforceIsAdmin(); 608 609 if (enabled) { 610 // Do not allow oem unlock to be enabled if it's disallowed by a user restriction. 611 enforceUserRestriction(UserManager.DISALLOW_OEM_UNLOCK); 612 enforceUserRestriction(UserManager.DISALLOW_FACTORY_RESET); 613 } 614 synchronized (mLock) { 615 doSetOemUnlockEnabledLocked(enabled); 616 computeAndWriteDigestLocked(); 617 } 618 } 619 620 @Override 621 public boolean getOemUnlockEnabled() { 622 enforceOemUnlockReadPermission(); 623 return doGetOemUnlockEnabled(); 624 } 625 626 @Override 627 public int getFlashLockState() { 628 enforceOemUnlockReadPermission(); 629 String locked = SystemProperties.get(FLASH_LOCK_PROP); 630 switch (locked) { 631 case FLASH_LOCK_LOCKED: 632 return PersistentDataBlockManager.FLASH_LOCK_LOCKED; 633 case FLASH_LOCK_UNLOCKED: 634 return PersistentDataBlockManager.FLASH_LOCK_UNLOCKED; 635 default: 636 return PersistentDataBlockManager.FLASH_LOCK_UNKNOWN; 637 } 638 } 639 640 @Override 641 public int getDataBlockSize() { 642 enforcePersistentDataBlockAccess(); 643 644 DataInputStream inputStream; 645 try { 646 inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile))); 647 } catch (FileNotFoundException e) { 648 Slog.e(TAG, "partition not available"); 649 return 0; 650 } 651 652 try { 653 synchronized (mLock) { 654 return getTotalDataSizeLocked(inputStream); 655 } 656 } catch (IOException e) { 657 Slog.e(TAG, "error reading data block size"); 658 return 0; 659 } finally { 660 IoUtils.closeQuietly(inputStream); 661 } 662 } 663 664 private void enforcePersistentDataBlockAccess() { 665 if (mContext.checkCallingPermission(Manifest.permission.ACCESS_PDB_STATE) 666 != PackageManager.PERMISSION_GRANTED) { 667 enforceUid(Binder.getCallingUid()); 668 } 669 } 670 671 @Override 672 public long getMaximumDataBlockSize() { 673 enforceUid(Binder.getCallingUid()); 674 return doGetMaximumDataBlockSize(); 675 } 676 677 @Override 678 public boolean hasFrpCredentialHandle() { 679 enforcePersistentDataBlockAccess(); 680 try { 681 return mInternalService.getFrpCredentialHandle() != null; 682 } catch (IllegalStateException e) { 683 Slog.e(TAG, "error reading frp handle", e); 684 throw new UnsupportedOperationException("cannot read frp credential"); 685 } 686 } 687 688 @Override 689 public String getPersistentDataPackageName() { 690 enforcePersistentDataBlockAccess(); 691 return mContext.getString(R.string.config_persistentDataPackageName); 692 } 693 694 @Override 695 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 696 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 697 698 pw.println("mDataBlockFile: " + mDataBlockFile); 699 pw.println("mIsRunningDSU: " + mIsRunningDSU); 700 pw.println("mInitDoneSignal: " + mInitDoneSignal); 701 pw.println("mAllowedUid: " + mAllowedUid); 702 pw.println("mBlockDeviceSize: " + mBlockDeviceSize); 703 synchronized (mLock) { 704 pw.println("mIsWritable: " + mIsWritable); 705 } 706 } 707 }; 708 709 private PersistentDataBlockManagerInternal mInternalService = 710 new PersistentDataBlockManagerInternal() { 711 712 @Override 713 public void setFrpCredentialHandle(byte[] handle) { 714 writeInternal(handle, getFrpCredentialDataOffset(), MAX_FRP_CREDENTIAL_HANDLE_SIZE); 715 } 716 717 @Override 718 public byte[] getFrpCredentialHandle() { 719 return readInternal(getFrpCredentialDataOffset(), MAX_FRP_CREDENTIAL_HANDLE_SIZE); 720 } 721 722 @Override 723 public void setTestHarnessModeData(byte[] data) { 724 writeInternal(data, getTestHarnessModeDataOffset(), MAX_TEST_MODE_DATA_SIZE); 725 } 726 727 @Override 728 public byte[] getTestHarnessModeData() { 729 byte[] data = readInternal(getTestHarnessModeDataOffset(), MAX_TEST_MODE_DATA_SIZE); 730 if (data == null) { 731 return new byte[0]; 732 } 733 return data; 734 } 735 736 @Override 737 public void clearTestHarnessModeData() { 738 int size = Math.min(MAX_TEST_MODE_DATA_SIZE, getTestHarnessModeData().length) + 4; 739 writeDataBuffer(getTestHarnessModeDataOffset(), ByteBuffer.allocate(size)); 740 } 741 742 @Override 743 public int getAllowedUid() { 744 return mAllowedUid; 745 } 746 747 private void writeInternal(byte[] data, long offset, int dataLength) { 748 checkArgument(data == null || data.length > 0, "data must be null or non-empty"); 749 checkArgument( 750 data == null || data.length <= dataLength, 751 "data must not be longer than " + dataLength); 752 753 ByteBuffer dataBuffer = ByteBuffer.allocate(dataLength + 4); 754 dataBuffer.putInt(data == null ? 0 : data.length); 755 if (data != null) { 756 dataBuffer.put(data); 757 } 758 dataBuffer.flip(); 759 760 writeDataBuffer(offset, dataBuffer); 761 } 762 763 private void writeDataBuffer(long offset, ByteBuffer dataBuffer) { 764 synchronized (mLock) { 765 if (!mIsWritable) { 766 return; 767 } 768 try { 769 FileChannel channel = getBlockOutputChannel(); 770 channel.position(offset); 771 channel.write(dataBuffer); 772 channel.force(true); 773 } catch (IOException e) { 774 Slog.e(TAG, "unable to access persistent partition", e); 775 return; 776 } 777 778 computeAndWriteDigestLocked(); 779 } 780 } 781 782 private byte[] readInternal(long offset, int maxLength) { 783 if (!enforceChecksumValidity()) { 784 throw new IllegalStateException("invalid checksum"); 785 } 786 787 DataInputStream inputStream; 788 try { 789 inputStream = new DataInputStream( 790 new FileInputStream(new File(mDataBlockFile))); 791 } catch (FileNotFoundException e) { 792 throw new IllegalStateException("persistent partition not available"); 793 } 794 795 try { 796 synchronized (mLock) { 797 inputStream.skip(offset); 798 int length = inputStream.readInt(); 799 if (length <= 0 || length > maxLength) { 800 return null; 801 } 802 byte[] bytes = new byte[length]; 803 inputStream.readFully(bytes); 804 return bytes; 805 } 806 } catch (IOException e) { 807 throw new IllegalStateException("persistent partition not readable", e); 808 } finally { 809 IoUtils.closeQuietly(inputStream); 810 } 811 } 812 813 @Override 814 public void forceOemUnlockEnabled(boolean enabled) { 815 synchronized (mLock) { 816 doSetOemUnlockEnabledLocked(enabled); 817 computeAndWriteDigestLocked(); 818 } 819 } 820 }; 821 } 822