1 /* 2 * Copyright (C) 2016 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.recoverysystem; 18 19 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME; 20 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED; 21 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_NONE; 22 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE; 23 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH; 24 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_UNSPECIFIED; 25 import static android.os.RecoverySystem.ResumeOnRebootRebootErrorCode; 26 import static android.os.UserHandle.USER_SYSTEM; 27 import static android.ota.nano.OtaPackageMetadata.ApexMetadata; 28 29 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE; 30 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER; 31 32 import android.annotation.IntDef; 33 import android.apex.CompressedApexInfo; 34 import android.apex.CompressedApexInfoList; 35 import android.content.Context; 36 import android.content.IntentSender; 37 import android.content.SharedPreferences; 38 import android.content.pm.PackageManager; 39 import android.hardware.boot.IBootControl; 40 import android.net.LocalSocket; 41 import android.net.LocalSocketAddress; 42 import android.os.Binder; 43 import android.os.Environment; 44 import android.os.IRecoverySystem; 45 import android.os.IRecoverySystemProgressListener; 46 import android.os.PowerManager; 47 import android.os.Process; 48 import android.os.RecoverySystem; 49 import android.os.RemoteException; 50 import android.os.ResultReceiver; 51 import android.os.ServiceManager; 52 import android.os.ShellCallback; 53 import android.os.SystemProperties; 54 import android.provider.DeviceConfig; 55 import android.sysprop.ApexProperties; 56 import android.util.ArrayMap; 57 import android.util.ArraySet; 58 import android.util.FastImmutableArraySet; 59 import android.util.Log; 60 import android.util.Slog; 61 62 import com.android.internal.annotations.GuardedBy; 63 import com.android.internal.annotations.VisibleForTesting; 64 import com.android.internal.util.FrameworkStatsLog; 65 import com.android.internal.widget.LockSettingsInternal; 66 import com.android.internal.widget.RebootEscrowListener; 67 import com.android.server.LocalServices; 68 import com.android.server.SystemService; 69 import com.android.server.pm.ApexManager; 70 import com.android.server.recoverysystem.hal.BootControlHIDL; 71 72 import libcore.io.IoUtils; 73 74 import java.io.DataInputStream; 75 import java.io.DataOutputStream; 76 import java.io.File; 77 import java.io.FileDescriptor; 78 import java.io.FileWriter; 79 import java.io.IOException; 80 import java.io.InputStream; 81 import java.nio.charset.StandardCharsets; 82 import java.util.ArrayList; 83 import java.util.Arrays; 84 import java.util.List; 85 import java.util.zip.ZipEntry; 86 import java.util.zip.ZipFile; 87 88 /** 89 * The recovery system service is responsible for coordinating recovery related 90 * functions on the device. It sets up (or clears) the bootloader control block 91 * (BCB), which will be read by the bootloader and the recovery image. It also 92 * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the 93 * /data partition so that it can be accessed under the recovery image. 94 */ 95 public class RecoverySystemService extends IRecoverySystem.Stub implements RebootEscrowListener { 96 private static final String TAG = "RecoverySystemService"; 97 private static final boolean DEBUG = false; 98 99 // The socket at /dev/socket/uncrypt to communicate with uncrypt. 100 private static final String UNCRYPT_SOCKET = "uncrypt"; 101 102 // The init services that communicate with /system/bin/uncrypt. 103 @VisibleForTesting 104 static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt"; 105 @VisibleForTesting 106 static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb"; 107 @VisibleForTesting 108 static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb"; 109 @VisibleForTesting 110 static final String AB_UPDATE = "ro.build.ab_update"; 111 112 private static final Object sRequestLock = new Object(); 113 114 private static final int SOCKET_CONNECTION_MAX_RETRY = 30; 115 116 static final String REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX = "_request_lskf_timestamp"; 117 static final String REQUEST_LSKF_COUNT_PREF_SUFFIX = "_request_lskf_count"; 118 119 static final String LSKF_CAPTURED_TIMESTAMP_PREF = "lskf_captured_timestamp"; 120 static final String LSKF_CAPTURED_COUNT_PREF = "lskf_captured_count"; 121 122 private final Injector mInjector; 123 private final Context mContext; 124 125 @GuardedBy("this") 126 private final ArrayMap<String, IntentSender> mCallerPendingRequest = new ArrayMap<>(); 127 @GuardedBy("this") 128 private final ArraySet<String> mCallerPreparedForReboot = new ArraySet<>(); 129 130 /** 131 * Need to prepare for resume on reboot. 132 */ 133 private static final int ROR_NEED_PREPARATION = 0; 134 /** 135 * Resume on reboot has been prepared, notify the caller. 136 */ 137 private static final int ROR_SKIP_PREPARATION_AND_NOTIFY = 1; 138 /** 139 * Resume on reboot has been requested. Caller won't be notified until the preparation is done. 140 */ 141 private static final int ROR_SKIP_PREPARATION_NOT_NOTIFY = 2; 142 143 /** 144 * The caller never requests for resume on reboot, no need for clear. 145 */ 146 private static final int ROR_NOT_REQUESTED = 0; 147 /** 148 * Clear the resume on reboot preparation state. 149 */ 150 private static final int ROR_REQUESTED_NEED_CLEAR = 1; 151 /** 152 * The caller has requested for resume on reboot. No need for clear since other callers may 153 * exist. 154 */ 155 private static final int ROR_REQUESTED_SKIP_CLEAR = 2; 156 157 /** 158 * The action to perform upon new resume on reboot prepare request for a given client. 159 */ 160 @IntDef({ROR_NEED_PREPARATION, 161 ROR_SKIP_PREPARATION_AND_NOTIFY, 162 ROR_SKIP_PREPARATION_NOT_NOTIFY}) 163 private @interface ResumeOnRebootActionsOnRequest { 164 } 165 166 /** 167 * The action to perform upon resume on reboot clear request for a given client. 168 */ 169 @IntDef({ROR_NOT_REQUESTED, 170 ROR_REQUESTED_NEED_CLEAR, 171 ROR_REQUESTED_SKIP_CLEAR}) 172 private @interface ResumeOnRebootActionsOnClear { 173 } 174 175 /** 176 * Fatal arm escrow errors from lock settings that means the RoR is in a bad state. So clients 177 * need to prepare RoR again. 178 */ 179 static final FastImmutableArraySet<Integer> FATAL_ARM_ESCROW_ERRORS = 180 new FastImmutableArraySet<>(new Integer[]{ 181 LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY, 182 LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER, 183 LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH, 184 LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY, 185 LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE, 186 }); 187 188 /** 189 * The error details for ArmRebootEscrow. It contains error codes from RecoverySystemService 190 * and LockSettingsService. 191 */ 192 static class RebootPreparationError { 193 final @ResumeOnRebootRebootErrorCode int mRebootErrorCode; 194 final int mProviderErrorCode; // The supplemental error code from lock settings 195 RebootPreparationError(int rebootErrorCode, int providerErrorCode)196 RebootPreparationError(int rebootErrorCode, int providerErrorCode) { 197 mRebootErrorCode = rebootErrorCode; 198 mProviderErrorCode = providerErrorCode; 199 } 200 getErrorCodeForMetrics()201 int getErrorCodeForMetrics() { 202 // The ResumeOnRebootRebootErrorCode are aligned with 1000; so it's safe to add them 203 // for metrics purpose. 204 return mRebootErrorCode + mProviderErrorCode; 205 } 206 } 207 208 /** 209 * Manages shared preference, i.e. the storage used for metrics reporting. 210 */ 211 public static class PreferencesManager { 212 private static final String METRICS_DIR = "recovery_system"; 213 private static final String METRICS_PREFS_FILE = "RecoverySystemMetricsPrefs.xml"; 214 215 protected final SharedPreferences mSharedPreferences; 216 private final File mMetricsPrefsFile; 217 PreferencesManager(Context context)218 PreferencesManager(Context context) { 219 File prefsDir = new File(Environment.getDataSystemCeDirectory(USER_SYSTEM), 220 METRICS_DIR); 221 mMetricsPrefsFile = new File(prefsDir, METRICS_PREFS_FILE); 222 mSharedPreferences = context.getSharedPreferences(mMetricsPrefsFile, 0); 223 } 224 225 /** Reads the value of a given key with type long. **/ getLong(String key, long defaultValue)226 public long getLong(String key, long defaultValue) { 227 return mSharedPreferences.getLong(key, defaultValue); 228 } 229 230 /** Reads the value of a given key with type int. **/ getInt(String key, int defaultValue)231 public int getInt(String key, int defaultValue) { 232 return mSharedPreferences.getInt(key, defaultValue); 233 } 234 235 /** Stores the value of a given key with type long. **/ putLong(String key, long value)236 public void putLong(String key, long value) { 237 mSharedPreferences.edit().putLong(key, value).commit(); 238 } 239 240 /** Stores the value of a given key with type int. **/ putInt(String key, int value)241 public void putInt(String key, int value) { 242 mSharedPreferences.edit().putInt(key, value).commit(); 243 } 244 245 /** Increments the value of a given key with type int. **/ incrementIntKey(String key, int defaultInitialValue)246 public synchronized void incrementIntKey(String key, int defaultInitialValue) { 247 int oldValue = getInt(key, defaultInitialValue); 248 putInt(key, oldValue + 1); 249 } 250 251 /** Delete the preference file and cleanup all metrics storage. **/ deletePrefsFile()252 public void deletePrefsFile() { 253 if (!mMetricsPrefsFile.delete()) { 254 Slog.w(TAG, "Failed to delete metrics prefs"); 255 } 256 } 257 } 258 259 static class Injector { 260 protected final Context mContext; 261 protected final PreferencesManager mPrefs; 262 Injector(Context context)263 Injector(Context context) { 264 mContext = context; 265 mPrefs = new PreferencesManager(context); 266 } 267 getContext()268 public Context getContext() { 269 return mContext; 270 } 271 getLockSettingsService()272 public LockSettingsInternal getLockSettingsService() { 273 return LocalServices.getService(LockSettingsInternal.class); 274 } 275 getPowerManager()276 public PowerManager getPowerManager() { 277 return (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 278 } 279 systemPropertiesGet(String key)280 public String systemPropertiesGet(String key) { 281 return SystemProperties.get(key); 282 } 283 systemPropertiesSet(String key, String value)284 public void systemPropertiesSet(String key, String value) { 285 SystemProperties.set(key, value); 286 } 287 uncryptPackageFileDelete()288 public boolean uncryptPackageFileDelete() { 289 return RecoverySystem.UNCRYPT_PACKAGE_FILE.delete(); 290 } 291 getUncryptPackageFileName()292 public String getUncryptPackageFileName() { 293 return RecoverySystem.UNCRYPT_PACKAGE_FILE.getName(); 294 } 295 getUncryptPackageFileWriter()296 public FileWriter getUncryptPackageFileWriter() throws IOException { 297 return new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE); 298 } 299 connectService()300 public UncryptSocket connectService() { 301 UncryptSocket socket = new UncryptSocket(); 302 if (!socket.connectService()) { 303 socket.close(); 304 return null; 305 } 306 return socket; 307 } 308 309 /** 310 * Throws remote exception if there's an error getting the boot control HAL. 311 * Returns null if the boot control HAL's version is older than V1_2. 312 */ getBootControl()313 public IBootControl getBootControl() throws RemoteException { 314 String serviceName = IBootControl.DESCRIPTOR + "/default"; 315 if (ServiceManager.isDeclared(serviceName)) { 316 Slog.i(TAG, 317 "AIDL version of BootControl HAL present, using instance " + serviceName); 318 return IBootControl.Stub.asInterface( 319 ServiceManager.waitForDeclaredService(serviceName)); 320 } 321 322 IBootControl bootcontrol = BootControlHIDL.getService(); 323 if (!BootControlHIDL.isServicePresent()) { 324 Slog.e(TAG, "Neither AIDL nor HIDL version of the BootControl HAL is present."); 325 return null; 326 } 327 328 if (!BootControlHIDL.isV1_2ServicePresent()) { 329 Slog.w(TAG, "Device doesn't implement boot control HAL V1_2."); 330 return null; 331 } 332 return bootcontrol; 333 } 334 threadSleep(long millis)335 public void threadSleep(long millis) throws InterruptedException { 336 Thread.sleep(millis); 337 } 338 getUidFromPackageName(String packageName)339 public int getUidFromPackageName(String packageName) { 340 try { 341 return mContext.getPackageManager().getPackageUidAsUser(packageName, USER_SYSTEM); 342 } catch (PackageManager.NameNotFoundException e) { 343 Slog.w(TAG, "Failed to find uid for " + packageName); 344 } 345 return -1; 346 } 347 getMetricsPrefs()348 public PreferencesManager getMetricsPrefs() { 349 return mPrefs; 350 } 351 getCurrentTimeMillis()352 public long getCurrentTimeMillis() { 353 return System.currentTimeMillis(); 354 } 355 reportRebootEscrowPreparationMetrics(int uid, @ResumeOnRebootActionsOnRequest int requestResult, int requestedClientCount)356 public void reportRebootEscrowPreparationMetrics(int uid, 357 @ResumeOnRebootActionsOnRequest int requestResult, int requestedClientCount) { 358 FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_PREPARATION_REPORTED, uid, 359 requestResult, requestedClientCount); 360 } 361 reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, int requestedToLskfCapturedDurationInSeconds)362 public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, 363 int requestedToLskfCapturedDurationInSeconds) { 364 FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_LSKF_CAPTURE_REPORTED, uid, 365 requestedClientCount, requestedToLskfCapturedDurationInSeconds); 366 } 367 reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount, int requestCount, boolean slotSwitch, boolean serverBased, int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts)368 public void reportRebootEscrowRebootMetrics(int errorCode, int uid, 369 int preparedClientCount, int requestCount, boolean slotSwitch, boolean serverBased, 370 int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) { 371 FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_REBOOT_REPORTED, errorCode, 372 uid, preparedClientCount, requestCount, slotSwitch, serverBased, 373 lskfCapturedToRebootDurationInSeconds, lskfCapturedCounts); 374 } 375 } 376 377 /** 378 * Handles the lifecycle events for the RecoverySystemService. 379 */ 380 public static final class Lifecycle extends SystemService { 381 private RecoverySystemService mRecoverySystemService; 382 Lifecycle(Context context)383 public Lifecycle(Context context) { 384 super(context); 385 } 386 387 @Override onBootPhase(int phase)388 public void onBootPhase(int phase) { 389 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 390 mRecoverySystemService.onSystemServicesReady(); 391 } 392 } 393 394 @Override onStart()395 public void onStart() { 396 mRecoverySystemService = new RecoverySystemService(getContext()); 397 publishBinderService(Context.RECOVERY_SERVICE, mRecoverySystemService); 398 } 399 } 400 RecoverySystemService(Context context)401 private RecoverySystemService(Context context) { 402 this(new Injector(context)); 403 } 404 405 @VisibleForTesting RecoverySystemService(Injector injector)406 RecoverySystemService(Injector injector) { 407 mInjector = injector; 408 mContext = injector.getContext(); 409 } 410 411 @VisibleForTesting onSystemServicesReady()412 void onSystemServicesReady() { 413 LockSettingsInternal lockSettings = mInjector.getLockSettingsService(); 414 if (lockSettings == null) { 415 Slog.e(TAG, "Failed to get lock settings service, skipping set" 416 + " RebootEscrowListener"); 417 return; 418 } 419 lockSettings.setRebootEscrowListener(this); 420 } 421 422 @Override // Binder call uncrypt(String filename, IRecoverySystemProgressListener listener)423 public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) { 424 if (DEBUG) Slog.d(TAG, "uncrypt: " + filename); 425 426 synchronized (sRequestLock) { 427 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); 428 429 if (!checkAndWaitForUncryptService()) { 430 Slog.e(TAG, "uncrypt service is unavailable."); 431 return false; 432 } 433 434 // Write the filename into uncrypt package file to be read by 435 // uncrypt. 436 mInjector.uncryptPackageFileDelete(); 437 438 try (FileWriter uncryptFile = mInjector.getUncryptPackageFileWriter()) { 439 uncryptFile.write(filename + "\n"); 440 } catch (IOException e) { 441 Slog.e(TAG, "IOException when writing \"" 442 + mInjector.getUncryptPackageFileName() + "\":", e); 443 return false; 444 } 445 446 // Trigger uncrypt via init. 447 mInjector.systemPropertiesSet("ctl.start", "uncrypt"); 448 449 // Connect to the uncrypt service socket. 450 UncryptSocket socket = mInjector.connectService(); 451 if (socket == null) { 452 Slog.e(TAG, "Failed to connect to uncrypt socket"); 453 return false; 454 } 455 456 // Read the status from the socket. 457 try { 458 int lastStatus = Integer.MIN_VALUE; 459 while (true) { 460 int status = socket.getPercentageUncrypted(); 461 // Avoid flooding the log with the same message. 462 if (status == lastStatus && lastStatus != Integer.MIN_VALUE) { 463 continue; 464 } 465 lastStatus = status; 466 467 if (status >= 0 && status <= 100) { 468 // Update status 469 Slog.i(TAG, "uncrypt read status: " + status); 470 if (listener != null) { 471 try { 472 listener.onProgress(status); 473 } catch (RemoteException ignored) { 474 Slog.w(TAG, "RemoteException when posting progress"); 475 } 476 } 477 if (status == 100) { 478 Slog.i(TAG, "uncrypt successfully finished."); 479 // Ack receipt of the final status code. uncrypt 480 // waits for the ack so the socket won't be 481 // destroyed before we receive the code. 482 socket.sendAck(); 483 break; 484 } 485 } else { 486 // Error in /system/bin/uncrypt. 487 Slog.e(TAG, "uncrypt failed with status: " + status); 488 // Ack receipt of the final status code. uncrypt waits 489 // for the ack so the socket won't be destroyed before 490 // we receive the code. 491 socket.sendAck(); 492 return false; 493 } 494 } 495 } catch (IOException e) { 496 Slog.e(TAG, "IOException when reading status: ", e); 497 return false; 498 } finally { 499 socket.close(); 500 } 501 502 return true; 503 } 504 } 505 506 @Override // Binder call clearBcb()507 public boolean clearBcb() { 508 if (DEBUG) Slog.d(TAG, "clearBcb"); 509 synchronized (sRequestLock) { 510 return setupOrClearBcb(false, null); 511 } 512 } 513 514 @Override // Binder call setupBcb(String command)515 public boolean setupBcb(String command) { 516 if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]"); 517 synchronized (sRequestLock) { 518 return setupOrClearBcb(true, command); 519 } 520 } 521 522 @Override // Binder call rebootRecoveryWithCommand(String command)523 public void rebootRecoveryWithCommand(String command) { 524 if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]"); 525 synchronized (sRequestLock) { 526 if (!setupOrClearBcb(true, command)) { 527 return; 528 } 529 530 // Having set up the BCB, go ahead and reboot. 531 PowerManager pm = mInjector.getPowerManager(); 532 pm.reboot(PowerManager.REBOOT_RECOVERY); 533 } 534 } 535 enforcePermissionForResumeOnReboot()536 private void enforcePermissionForResumeOnReboot() { 537 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.RECOVERY) 538 != PackageManager.PERMISSION_GRANTED 539 && mContext.checkCallingOrSelfPermission(android.Manifest.permission.REBOOT) 540 != PackageManager.PERMISSION_GRANTED) { 541 throw new SecurityException("Caller must have " + android.Manifest.permission.RECOVERY 542 + " or " + android.Manifest.permission.REBOOT + " for resume on reboot."); 543 } 544 } 545 reportMetricsOnRequestLskf(String packageName, int requestResult)546 private void reportMetricsOnRequestLskf(String packageName, int requestResult) { 547 int uid = mInjector.getUidFromPackageName(packageName); 548 int pendingRequestCount; 549 synchronized (this) { 550 pendingRequestCount = mCallerPendingRequest.size(); 551 } 552 553 // Save the timestamp and request count for new ror request 554 PreferencesManager prefs = mInjector.getMetricsPrefs(); 555 prefs.putLong(packageName + REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX, 556 mInjector.getCurrentTimeMillis()); 557 prefs.incrementIntKey(packageName + REQUEST_LSKF_COUNT_PREF_SUFFIX, 0); 558 559 mInjector.reportRebootEscrowPreparationMetrics(uid, requestResult, pendingRequestCount); 560 } 561 562 @Override // Binder call requestLskf(String packageName, IntentSender intentSender)563 public boolean requestLskf(String packageName, IntentSender intentSender) { 564 enforcePermissionForResumeOnReboot(); 565 566 if (packageName == null) { 567 Slog.w(TAG, "Missing packageName when requesting lskf."); 568 return false; 569 } 570 571 @ResumeOnRebootActionsOnRequest int action = updateRoRPreparationStateOnNewRequest( 572 packageName, intentSender); 573 reportMetricsOnRequestLskf(packageName, action); 574 575 switch (action) { 576 case ROR_SKIP_PREPARATION_AND_NOTIFY: 577 // We consider the preparation done if someone else has prepared. 578 sendPreparedForRebootIntentIfNeeded(intentSender); 579 return true; 580 case ROR_SKIP_PREPARATION_NOT_NOTIFY: 581 return true; 582 case ROR_NEED_PREPARATION: 583 final long origId = Binder.clearCallingIdentity(); 584 try { 585 LockSettingsInternal lockSettings = mInjector.getLockSettingsService(); 586 if (lockSettings == null) { 587 Slog.e(TAG, "Failed to get lock settings service, skipping" 588 + " prepareRebootEscrow"); 589 return false; 590 } 591 // Clear the RoR preparation state if lock settings reports an failure. 592 if (!lockSettings.prepareRebootEscrow()) { 593 clearRoRPreparationState(); 594 return false; 595 } 596 return true; 597 } finally { 598 Binder.restoreCallingIdentity(origId); 599 } 600 default: 601 throw new IllegalStateException("Unsupported action type on new request " + action); 602 } 603 } 604 605 // Checks and updates the resume on reboot preparation state. updateRoRPreparationStateOnNewRequest( String packageName, IntentSender intentSender)606 private synchronized @ResumeOnRebootActionsOnRequest int updateRoRPreparationStateOnNewRequest( 607 String packageName, IntentSender intentSender) { 608 if (!mCallerPreparedForReboot.isEmpty()) { 609 if (mCallerPreparedForReboot.contains(packageName)) { 610 Slog.i(TAG, "RoR already has prepared for " + packageName); 611 } 612 613 // Someone else has prepared. Consider the preparation done, and send back the intent. 614 mCallerPreparedForReboot.add(packageName); 615 return ROR_SKIP_PREPARATION_AND_NOTIFY; 616 } 617 618 boolean needPreparation = mCallerPendingRequest.isEmpty(); 619 if (mCallerPendingRequest.containsKey(packageName)) { 620 Slog.i(TAG, "Duplicate RoR preparation request for " + packageName); 621 } 622 // Update the request with the new intentSender. 623 mCallerPendingRequest.put(packageName, intentSender); 624 return needPreparation ? ROR_NEED_PREPARATION : ROR_SKIP_PREPARATION_NOT_NOTIFY; 625 } 626 reportMetricsOnPreparedForReboot()627 private void reportMetricsOnPreparedForReboot() { 628 long currentTimestamp = mInjector.getCurrentTimeMillis(); 629 630 List<String> preparedClients; 631 synchronized (this) { 632 preparedClients = new ArrayList<>(mCallerPreparedForReboot); 633 } 634 635 // Save the timestamp & lskf capture count for lskf capture 636 PreferencesManager prefs = mInjector.getMetricsPrefs(); 637 prefs.putLong(LSKF_CAPTURED_TIMESTAMP_PREF, currentTimestamp); 638 prefs.incrementIntKey(LSKF_CAPTURED_COUNT_PREF, 0); 639 640 for (String packageName : preparedClients) { 641 int uid = mInjector.getUidFromPackageName(packageName); 642 643 int durationSeconds = -1; 644 long requestLskfTimestamp = prefs.getLong( 645 packageName + REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX, -1); 646 if (requestLskfTimestamp != -1 && currentTimestamp > requestLskfTimestamp) { 647 durationSeconds = (int) (currentTimestamp - requestLskfTimestamp) / 1000; 648 } 649 Slog.i(TAG, String.format("Reporting lskf captured, lskf capture takes %d seconds for" 650 + " package %s", durationSeconds, packageName)); 651 mInjector.reportRebootEscrowLskfCapturedMetrics(uid, preparedClients.size(), 652 durationSeconds); 653 } 654 } 655 656 @Override onPreparedForReboot(boolean ready)657 public void onPreparedForReboot(boolean ready) { 658 if (!ready) { 659 return; 660 } 661 updateRoRPreparationStateOnPreparedForReboot(); 662 reportMetricsOnPreparedForReboot(); 663 } 664 updateRoRPreparationStateOnPreparedForReboot()665 private synchronized void updateRoRPreparationStateOnPreparedForReboot() { 666 if (!mCallerPreparedForReboot.isEmpty()) { 667 Slog.w(TAG, "onPreparedForReboot called when some clients have prepared."); 668 } 669 670 if (mCallerPendingRequest.isEmpty()) { 671 Slog.w(TAG, "onPreparedForReboot called but no client has requested."); 672 } 673 674 // Send intents to notify callers 675 for (int i = 0; i < mCallerPendingRequest.size(); i++) { 676 sendPreparedForRebootIntentIfNeeded(mCallerPendingRequest.valueAt(i)); 677 mCallerPreparedForReboot.add(mCallerPendingRequest.keyAt(i)); 678 } 679 mCallerPendingRequest.clear(); 680 } 681 sendPreparedForRebootIntentIfNeeded(IntentSender intentSender)682 private void sendPreparedForRebootIntentIfNeeded(IntentSender intentSender) { 683 if (intentSender != null) { 684 try { 685 intentSender.sendIntent(null, 0, null, null, null); 686 } catch (IntentSender.SendIntentException e) { 687 Slog.w(TAG, "Could not send intent for prepared reboot: " + e.getMessage()); 688 } 689 } 690 } 691 692 @Override // Binder call clearLskf(String packageName)693 public boolean clearLskf(String packageName) { 694 enforcePermissionForResumeOnReboot(); 695 if (packageName == null) { 696 Slog.w(TAG, "Missing packageName when clearing lskf."); 697 return false; 698 } 699 // TODO(179105110) Clear the RoR metrics for the given packageName. 700 701 @ResumeOnRebootActionsOnClear int action = updateRoRPreparationStateOnClear(packageName); 702 switch (action) { 703 case ROR_NOT_REQUESTED: 704 Slog.w(TAG, "RoR clear called before preparation for caller " + packageName); 705 return true; 706 case ROR_REQUESTED_SKIP_CLEAR: 707 return true; 708 case ROR_REQUESTED_NEED_CLEAR: 709 final long origId = Binder.clearCallingIdentity(); 710 try { 711 LockSettingsInternal lockSettings = mInjector.getLockSettingsService(); 712 if (lockSettings == null) { 713 Slog.e(TAG, "Failed to get lock settings service, skipping" 714 + " clearRebootEscrow"); 715 return false; 716 } 717 718 return lockSettings.clearRebootEscrow(); 719 } finally { 720 Binder.restoreCallingIdentity(origId); 721 } 722 default: 723 throw new IllegalStateException("Unsupported action type on clear " + action); 724 } 725 } 726 updateRoRPreparationStateOnClear( String packageName)727 private synchronized @ResumeOnRebootActionsOnClear int updateRoRPreparationStateOnClear( 728 String packageName) { 729 if (!mCallerPreparedForReboot.contains(packageName) && !mCallerPendingRequest.containsKey( 730 packageName)) { 731 Slog.w(TAG, packageName + " hasn't prepared for resume on reboot"); 732 return ROR_NOT_REQUESTED; 733 } 734 mCallerPendingRequest.remove(packageName); 735 mCallerPreparedForReboot.remove(packageName); 736 737 // Check if others have prepared ROR. 738 boolean needClear = mCallerPendingRequest.isEmpty() && mCallerPreparedForReboot.isEmpty(); 739 return needClear ? ROR_REQUESTED_NEED_CLEAR : ROR_REQUESTED_SKIP_CLEAR; 740 } 741 isAbDevice()742 private boolean isAbDevice() { 743 return "true".equalsIgnoreCase(mInjector.systemPropertiesGet(AB_UPDATE)); 744 } 745 verifySlotForNextBoot(boolean slotSwitch)746 private boolean verifySlotForNextBoot(boolean slotSwitch) { 747 if (!isAbDevice()) { 748 Slog.w(TAG, "Device isn't a/b, skipping slot verification."); 749 return true; 750 } 751 752 IBootControl bootControl; 753 try { 754 bootControl = mInjector.getBootControl(); 755 } catch (RemoteException e) { 756 Slog.w(TAG, "Failed to get the boot control HAL " + e); 757 return false; 758 } 759 760 // TODO(xunchang) enforce boot control V1_2 HAL on devices using multi client RoR 761 if (bootControl == null) { 762 Slog.w(TAG, "Cannot get the boot control HAL, skipping slot verification."); 763 return true; 764 } 765 766 int current_slot; 767 int next_active_slot; 768 try { 769 current_slot = bootControl.getCurrentSlot(); 770 if (current_slot != 0 && current_slot != 1) { 771 throw new IllegalStateException("Current boot slot should be 0 or 1, got " 772 + current_slot); 773 } 774 next_active_slot = bootControl.getActiveBootSlot(); 775 } catch (RemoteException e) { 776 Slog.w(TAG, "Failed to query the active slots", e); 777 return false; 778 } 779 780 int expected_active_slot = current_slot; 781 if (slotSwitch) { 782 expected_active_slot = current_slot == 0 ? 1 : 0; 783 } 784 if (next_active_slot != expected_active_slot) { 785 Slog.w(TAG, "The next active boot slot doesn't match the expected value, " 786 + "expected " + expected_active_slot + ", got " + next_active_slot); 787 return false; 788 } 789 return true; 790 } 791 armRebootEscrow(String packageName, boolean slotSwitch)792 private RebootPreparationError armRebootEscrow(String packageName, 793 boolean slotSwitch) { 794 if (packageName == null) { 795 Slog.w(TAG, "Missing packageName when rebooting with lskf."); 796 return new RebootPreparationError( 797 RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME, ARM_REBOOT_ERROR_NONE); 798 } 799 if (!isLskfCaptured(packageName)) { 800 return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED, 801 ARM_REBOOT_ERROR_NONE); 802 } 803 804 if (!verifySlotForNextBoot(slotSwitch)) { 805 return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH, 806 ARM_REBOOT_ERROR_NONE); 807 } 808 809 final long origId = Binder.clearCallingIdentity(); 810 int providerErrorCode; 811 try { 812 LockSettingsInternal lockSettings = mInjector.getLockSettingsService(); 813 if (lockSettings == null) { 814 Slog.e(TAG, "Failed to get lock settings service, skipping" 815 + " armRebootEscrow"); 816 return new RebootPreparationError( 817 RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE, 818 ARM_REBOOT_ERROR_NO_PROVIDER); 819 } 820 providerErrorCode = lockSettings.armRebootEscrow(); 821 } finally { 822 Binder.restoreCallingIdentity(origId); 823 } 824 825 if (providerErrorCode != ARM_REBOOT_ERROR_NONE) { 826 Slog.w(TAG, "Failure to escrow key for reboot, providerErrorCode: " 827 + providerErrorCode); 828 return new RebootPreparationError( 829 RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE, providerErrorCode); 830 } 831 832 return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_NONE, 833 ARM_REBOOT_ERROR_NONE); 834 } 835 useServerBasedRoR()836 private boolean useServerBasedRoR() { 837 final long origId = Binder.clearCallingIdentity(); 838 try { 839 return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, 840 "server_based_ror_enabled", false); 841 } finally { 842 Binder.restoreCallingIdentity(origId); 843 } 844 } 845 reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch, RebootPreparationError escrowError)846 private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch, 847 RebootPreparationError escrowError) { 848 int uid = mInjector.getUidFromPackageName(packageName); 849 boolean serverBased = useServerBasedRoR(); 850 int preparedClientCount; 851 synchronized (this) { 852 preparedClientCount = mCallerPreparedForReboot.size(); 853 } 854 855 long currentTimestamp = mInjector.getCurrentTimeMillis(); 856 int durationSeconds = -1; 857 PreferencesManager prefs = mInjector.getMetricsPrefs(); 858 long lskfCapturedTimestamp = prefs.getLong(LSKF_CAPTURED_TIMESTAMP_PREF, -1); 859 if (lskfCapturedTimestamp != -1 && currentTimestamp > lskfCapturedTimestamp) { 860 durationSeconds = (int) (currentTimestamp - lskfCapturedTimestamp) / 1000; 861 } 862 863 int requestCount = prefs.getInt(packageName + REQUEST_LSKF_COUNT_PREF_SUFFIX, -1); 864 int lskfCapturedCount = prefs.getInt(LSKF_CAPTURED_COUNT_PREF, -1); 865 866 Slog.i(TAG, String.format("Reporting reboot with lskf, package name %s, client count %d," 867 + " request count %d, lskf captured count %d, duration since lskf captured" 868 + " %d seconds.", packageName, preparedClientCount, requestCount, 869 lskfCapturedCount, durationSeconds)); 870 mInjector.reportRebootEscrowRebootMetrics(escrowError.getErrorCodeForMetrics(), uid, 871 preparedClientCount, requestCount, slotSwitch, serverBased, durationSeconds, 872 lskfCapturedCount); 873 } 874 clearRoRPreparationState()875 private synchronized void clearRoRPreparationState() { 876 mCallerPendingRequest.clear(); 877 mCallerPreparedForReboot.clear(); 878 } 879 clearRoRPreparationStateOnRebootFailure(RebootPreparationError escrowError)880 private void clearRoRPreparationStateOnRebootFailure(RebootPreparationError escrowError) { 881 if (!FATAL_ARM_ESCROW_ERRORS.contains(escrowError.mProviderErrorCode)) { 882 return; 883 } 884 885 Slog.w(TAG, "Clearing resume on reboot states for all clients on arm escrow error: " 886 + escrowError.mProviderErrorCode); 887 clearRoRPreparationState(); 888 } 889 rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch)890 private @ResumeOnRebootRebootErrorCode int rebootWithLskfImpl(String packageName, String reason, 891 boolean slotSwitch) { 892 RebootPreparationError escrowError = armRebootEscrow(packageName, slotSwitch); 893 reportMetricsOnRebootWithLskf(packageName, slotSwitch, escrowError); 894 clearRoRPreparationStateOnRebootFailure(escrowError); 895 896 @ResumeOnRebootRebootErrorCode int errorCode = escrowError.mRebootErrorCode; 897 if (errorCode != RESUME_ON_REBOOT_REBOOT_ERROR_NONE) { 898 return errorCode; 899 } 900 901 // Clear the metrics prefs after a successful RoR reboot. 902 mInjector.getMetricsPrefs().deletePrefsFile(); 903 904 PowerManager pm = mInjector.getPowerManager(); 905 pm.reboot(reason); 906 return RESUME_ON_REBOOT_REBOOT_ERROR_UNSPECIFIED; 907 } 908 909 @Override // Binder call for the legacy rebootWithLskf rebootWithLskfAssumeSlotSwitch(String packageName, String reason)910 public @ResumeOnRebootRebootErrorCode int rebootWithLskfAssumeSlotSwitch(String packageName, 911 String reason) { 912 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); 913 return rebootWithLskfImpl(packageName, reason, true); 914 } 915 916 @Override // Binder call rebootWithLskf(String packageName, String reason, boolean slotSwitch)917 public @ResumeOnRebootRebootErrorCode int rebootWithLskf(String packageName, String reason, 918 boolean slotSwitch) { 919 enforcePermissionForResumeOnReboot(); 920 return rebootWithLskfImpl(packageName, reason, slotSwitch); 921 } 922 isUpdatableApexSupported()923 public static boolean isUpdatableApexSupported() { 924 return ApexProperties.updatable().orElse(false); 925 } 926 927 // Metadata should be no more than few MB, if it's larger than 100MB something is wrong. 928 private static final long APEX_INFO_SIZE_LIMIT = 24 * 1024 * 100; 929 getCompressedApexInfoList(String packageFile)930 private static CompressedApexInfoList getCompressedApexInfoList(String packageFile) 931 throws IOException { 932 try (ZipFile zipFile = new ZipFile(packageFile)) { 933 final ZipEntry entry = zipFile.getEntry("apex_info.pb"); 934 if (entry == null) { 935 return null; 936 } 937 if (entry.getSize() >= APEX_INFO_SIZE_LIMIT) { 938 throw new IllegalArgumentException("apex_info.pb has size " 939 + entry.getSize() 940 + " which is larger than the permitted limit" + APEX_INFO_SIZE_LIMIT); 941 } 942 if (entry.getSize() == 0) { 943 CompressedApexInfoList infoList = new CompressedApexInfoList(); 944 infoList.apexInfos = new CompressedApexInfo[0]; 945 return infoList; 946 } 947 Log.i(TAG, "Allocating " + entry.getSize() 948 + " bytes of memory to store OTA Metadata"); 949 byte[] data = new byte[(int) entry.getSize()]; 950 951 try (InputStream is = zipFile.getInputStream(entry)) { 952 int bytesRead = is.read(data); 953 String msg = "Read " + bytesRead + " when expecting " + data.length; 954 Log.e(TAG, msg); 955 if (bytesRead != data.length) { 956 throw new IOException(msg); 957 } 958 } 959 ApexMetadata metadata = ApexMetadata.parseFrom(data); 960 CompressedApexInfoList apexInfoList = new CompressedApexInfoList(); 961 apexInfoList.apexInfos = 962 Arrays.stream(metadata.apexInfo).filter(apex -> apex.isCompressed).map(apex -> { 963 CompressedApexInfo info = new CompressedApexInfo(); 964 info.moduleName = apex.packageName; 965 info.decompressedSize = apex.decompressedSize; 966 info.versionCode = apex.version; 967 return info; 968 }).toArray(CompressedApexInfo[]::new); 969 return apexInfoList; 970 } 971 } 972 973 @Override allocateSpaceForUpdate(String packageFile)974 public boolean allocateSpaceForUpdate(String packageFile) { 975 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); 976 if (!isUpdatableApexSupported()) { 977 Log.i(TAG, "Updatable Apex not supported, " 978 + "allocateSpaceForUpdate does nothing."); 979 return true; 980 } 981 final long token = Binder.clearCallingIdentity(); 982 try { 983 CompressedApexInfoList apexInfoList = getCompressedApexInfoList(packageFile); 984 if (apexInfoList == null) { 985 Log.i(TAG, "apex_info.pb not present in OTA package. " 986 + "Assuming device doesn't support compressed" 987 + "APEX, continueing without allocating space."); 988 return true; 989 } 990 ApexManager apexManager = ApexManager.getInstance(); 991 apexManager.reserveSpaceForCompressedApex(apexInfoList); 992 return true; 993 } catch (RemoteException e) { 994 e.rethrowAsRuntimeException(); 995 } catch (IOException | UnsupportedOperationException e) { 996 Slog.e(TAG, "Failed to reserve space for compressed apex: ", e); 997 } finally { 998 Binder.restoreCallingIdentity(token); 999 } 1000 return false; 1001 } 1002 1003 @Override // Binder call isLskfCaptured(String packageName)1004 public boolean isLskfCaptured(String packageName) { 1005 enforcePermissionForResumeOnReboot(); 1006 boolean captured; 1007 synchronized (this) { 1008 captured = mCallerPreparedForReboot.contains(packageName); 1009 } 1010 1011 if (!captured) { 1012 Slog.i(TAG, "Reboot requested before prepare completed for caller " 1013 + packageName); 1014 return false; 1015 } 1016 return true; 1017 } 1018 1019 /** 1020 * Check if any of the init services is still running. If so, we cannot 1021 * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise 1022 * it may break the socket communication since init creates / deletes 1023 * the socket (/dev/socket/uncrypt) on service start / exit. 1024 */ checkAndWaitForUncryptService()1025 private boolean checkAndWaitForUncryptService() { 1026 for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { 1027 final String uncryptService = mInjector.systemPropertiesGet(INIT_SERVICE_UNCRYPT); 1028 final String setupBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_SETUP_BCB); 1029 final String clearBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_CLEAR_BCB); 1030 final boolean busy = "running".equals(uncryptService) 1031 || "running".equals(setupBcbService) || "running".equals(clearBcbService); 1032 if (DEBUG) { 1033 Slog.i(TAG, "retry: " + retry + " busy: " + busy 1034 + " uncrypt: [" + uncryptService + "]" 1035 + " setupBcb: [" + setupBcbService + "]" 1036 + " clearBcb: [" + clearBcbService + "]"); 1037 } 1038 1039 if (!busy) { 1040 return true; 1041 } 1042 1043 try { 1044 mInjector.threadSleep(1000); 1045 } catch (InterruptedException e) { 1046 Slog.w(TAG, "Interrupted:", e); 1047 } 1048 } 1049 1050 return false; 1051 } 1052 setupOrClearBcb(boolean isSetup, String command)1053 private boolean setupOrClearBcb(boolean isSetup, String command) { 1054 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); 1055 1056 final boolean available = checkAndWaitForUncryptService(); 1057 if (!available) { 1058 Slog.e(TAG, "uncrypt service is unavailable."); 1059 return false; 1060 } 1061 1062 if (isSetup) { 1063 mInjector.systemPropertiesSet("ctl.start", "setup-bcb"); 1064 } else { 1065 mInjector.systemPropertiesSet("ctl.start", "clear-bcb"); 1066 } 1067 1068 // Connect to the uncrypt service socket. 1069 UncryptSocket socket = mInjector.connectService(); 1070 if (socket == null) { 1071 Slog.e(TAG, "Failed to connect to uncrypt socket"); 1072 return false; 1073 } 1074 1075 try { 1076 // Send the BCB commands if it's to setup BCB. 1077 if (isSetup) { 1078 socket.sendCommand(command); 1079 } 1080 1081 // Read the status from the socket. 1082 int status = socket.getPercentageUncrypted(); 1083 1084 // Ack receipt of the status code. uncrypt waits for the ack so 1085 // the socket won't be destroyed before we receive the code. 1086 socket.sendAck(); 1087 1088 if (status == 100) { 1089 Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") 1090 + " bcb successfully finished."); 1091 } else { 1092 // Error in /system/bin/uncrypt. 1093 Slog.e(TAG, "uncrypt failed with status: " + status); 1094 return false; 1095 } 1096 } catch (IOException e) { 1097 Slog.e(TAG, "IOException when communicating with uncrypt:", e); 1098 return false; 1099 } finally { 1100 socket.close(); 1101 } 1102 1103 return true; 1104 } 1105 1106 /** 1107 * Provides a wrapper for the low-level details of framing packets sent to the uncrypt 1108 * socket. 1109 */ 1110 public static class UncryptSocket { 1111 private LocalSocket mLocalSocket; 1112 private DataInputStream mInputStream; 1113 private DataOutputStream mOutputStream; 1114 1115 /** 1116 * Attempt to connect to the uncrypt service. Connection will be retried for up to 1117 * {@link #SOCKET_CONNECTION_MAX_RETRY} times. If the connection is unsuccessful, the 1118 * socket will be closed. If the connection is successful, the connection must be closed 1119 * by the caller. 1120 * 1121 * @return true if connection was successful, false if unsuccessful 1122 */ connectService()1123 public boolean connectService() { 1124 mLocalSocket = new LocalSocket(); 1125 boolean done = false; 1126 // The uncrypt socket will be created by init upon receiving the 1127 // service request. It may not be ready by this point. So we will 1128 // keep retrying until success or reaching timeout. 1129 for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { 1130 try { 1131 mLocalSocket.connect(new LocalSocketAddress(UNCRYPT_SOCKET, 1132 LocalSocketAddress.Namespace.RESERVED)); 1133 done = true; 1134 break; 1135 } catch (IOException ignored) { 1136 try { 1137 Thread.sleep(1000); 1138 } catch (InterruptedException e) { 1139 Slog.w(TAG, "Interrupted:", e); 1140 } 1141 } 1142 } 1143 if (!done) { 1144 Slog.e(TAG, "Timed out connecting to uncrypt socket"); 1145 close(); 1146 return false; 1147 } 1148 1149 try { 1150 mInputStream = new DataInputStream(mLocalSocket.getInputStream()); 1151 mOutputStream = new DataOutputStream(mLocalSocket.getOutputStream()); 1152 } catch (IOException e) { 1153 close(); 1154 return false; 1155 } 1156 1157 return true; 1158 } 1159 1160 /** 1161 * Sends a command to the uncrypt service. 1162 * 1163 * @param command command to send to the uncrypt service 1164 * @throws IOException if there was an error writing to the socket 1165 */ sendCommand(String command)1166 public void sendCommand(String command) throws IOException { 1167 byte[] cmdUtf8 = command.getBytes(StandardCharsets.UTF_8); 1168 mOutputStream.writeInt(cmdUtf8.length); 1169 mOutputStream.write(cmdUtf8, 0, cmdUtf8.length); 1170 } 1171 1172 /** 1173 * Reads the status from the uncrypt service which is usually represented as a percentage. 1174 * 1175 * @return an integer representing the percentage completed 1176 * @throws IOException if there was an error reading the socket 1177 */ getPercentageUncrypted()1178 public int getPercentageUncrypted() throws IOException { 1179 return mInputStream.readInt(); 1180 } 1181 1182 /** 1183 * Sends a confirmation to the uncrypt service. 1184 * 1185 * @throws IOException if there was an error writing to the socket 1186 */ sendAck()1187 public void sendAck() throws IOException { 1188 mOutputStream.writeInt(0); 1189 } 1190 1191 /** 1192 * Closes the socket and all underlying data streams. 1193 */ close()1194 public void close() { 1195 IoUtils.closeQuietly(mInputStream); 1196 IoUtils.closeQuietly(mOutputStream); 1197 IoUtils.closeQuietly(mLocalSocket); 1198 } 1199 } 1200 isCallerShell()1201 private boolean isCallerShell() { 1202 final int callingUid = Binder.getCallingUid(); 1203 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID; 1204 } 1205 enforceShell()1206 private void enforceShell() { 1207 if (!isCallerShell()) { 1208 throw new SecurityException("Caller must be shell"); 1209 } 1210 } 1211 1212 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1213 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1214 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 1215 enforceShell(); 1216 final long origId = Binder.clearCallingIdentity(); 1217 try { 1218 new RecoverySystemShellCommand(this).exec( 1219 this, in, out, err, args, callback, resultReceiver); 1220 } finally { 1221 Binder.restoreCallingIdentity(origId); 1222 } 1223 } 1224 } 1225