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