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