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