1e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao/* 2e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * Copyright (C) 2016 The Android Open Source Project 3e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * 4e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * Licensed under the Apache License, Version 2.0 (the "License"); 5e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * you may not use this file except in compliance with the License. 6e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * You may obtain a copy of the License at 7e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * 8e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * http://www.apache.org/licenses/LICENSE-2.0 9e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * 10e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * Unless required by applicable law or agreed to in writing, software 11e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * distributed under the License is distributed on an "AS IS" BASIS, 12e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * See the License for the specific language governing permissions and 14e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * limitations under the License. 15e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao */ 16e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 17e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baopackage com.android.server; 18e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 19e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.content.Context; 20dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Baoimport android.net.LocalSocket; 21dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Baoimport android.net.LocalSocketAddress; 22e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.os.IRecoverySystem; 23e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.os.IRecoverySystemProgressListener; 24794c8b0b3fe16051843c22232d58d6b184dde49bTao Baoimport android.os.PowerManager; 25e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.os.RecoverySystem; 26e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.os.RemoteException; 27e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.os.SystemProperties; 28e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.system.ErrnoException; 29e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.system.Os; 30e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport android.util.Slog; 31e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 32dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Baoimport libcore.io.IoUtils; 33dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao 34dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Baoimport java.io.DataInputStream; 35dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Baoimport java.io.DataOutputStream; 36e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport java.io.File; 37e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport java.io.FileWriter; 38e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baoimport java.io.IOException; 39e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 40e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao/** 41e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * The recovery system service is responsible for coordinating recovery related 42e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * functions on the device. It sets up (or clears) the bootloader control block 43e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * (BCB), which will be read by the bootloader and the recovery image. It also 44e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the 45e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao * /data partition so that it can be accessed under the recovery image. 46e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao */ 47e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Baopublic final class RecoverySystemService extends SystemService { 48e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao private static final String TAG = "RecoverySystemService"; 49e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao private static final boolean DEBUG = false; 50e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 51dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // The socket at /dev/socket/uncrypt to communicate with uncrypt. 52dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao private static final String UNCRYPT_SOCKET = "uncrypt"; 53dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao 54794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // The init services that communicate with /system/bin/uncrypt. 55794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt"; 56794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb"; 57794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb"; 58794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 59dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao private static final int SOCKET_CONNECTION_MAX_RETRY = 30; 60e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 61794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao private static final Object sRequestLock = new Object(); 62794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 63e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao private Context mContext; 64e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 65e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao public RecoverySystemService(Context context) { 66e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao super(context); 67e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao mContext = context; 68e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 69e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 70e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao @Override 71e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao public void onStart() { 72e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao publishBinderService(Context.RECOVERY_SERVICE, new BinderService()); 73e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 74e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 75e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao private final class BinderService extends IRecoverySystem.Stub { 76e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao @Override // Binder call 77e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) { 78e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao if (DEBUG) Slog.d(TAG, "uncrypt: " + filename); 79e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 80794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao synchronized (sRequestLock) { 81794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); 82e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 83794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao final boolean available = checkAndWaitForUncryptService(); 84794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (!available) { 85794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.e(TAG, "uncrypt service is unavailable."); 86794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return false; 87794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 88e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 89794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Write the filename into UNCRYPT_PACKAGE_FILE to be read by 90794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // uncrypt. 91794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao RecoverySystem.UNCRYPT_PACKAGE_FILE.delete(); 92e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 93794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) { 94794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao uncryptFile.write(filename + "\n"); 95794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } catch (IOException e) { 96794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.e(TAG, "IOException when writing \"" + 97794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e); 98794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return false; 99794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 100e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 101794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Trigger uncrypt via init. 102794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao SystemProperties.set("ctl.start", "uncrypt"); 103dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao 104794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Connect to the uncrypt service socket. 105794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao LocalSocket socket = connectService(); 106794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (socket == null) { 107794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.e(TAG, "Failed to connect to uncrypt socket"); 108794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return false; 109794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 110794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 111794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Read the status from the socket. 112794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao DataInputStream dis = null; 113794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao DataOutputStream dos = null; 114794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao try { 115794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao dis = new DataInputStream(socket.getInputStream()); 116794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao dos = new DataOutputStream(socket.getOutputStream()); 117794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao int lastStatus = Integer.MIN_VALUE; 118794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao while (true) { 119794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao int status = dis.readInt(); 120794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Avoid flooding the log with the same message. 121794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (status == lastStatus && lastStatus != Integer.MIN_VALUE) { 122794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao continue; 123e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 124794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao lastStatus = status; 125794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 126794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (status >= 0 && status <= 100) { 127794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Update status 128794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.i(TAG, "uncrypt read status: " + status); 129794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (listener != null) { 130794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao try { 131794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao listener.onProgress(status); 132794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } catch (RemoteException ignored) { 133794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.w(TAG, "RemoteException when posting progress"); 134794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 135794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 136794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (status == 100) { 137794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.i(TAG, "uncrypt successfully finished."); 138794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Ack receipt of the final status code. uncrypt 139794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // waits for the ack so the socket won't be 140794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // destroyed before we receive the code. 141794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao dos.writeInt(0); 142794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao break; 143794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 144794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } else { 145794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Error in /system/bin/uncrypt. 146794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.e(TAG, "uncrypt failed with status: " + status); 147794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Ack receipt of the final status code. uncrypt waits 148794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // for the ack so the socket won't be destroyed before 149794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // we receive the code. 150dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao dos.writeInt(0); 151794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return false; 152dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } 153e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 154794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } catch (IOException e) { 155794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.e(TAG, "IOException when reading status: ", e); 156794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return false; 157794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } finally { 158794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao IoUtils.closeQuietly(dis); 159794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao IoUtils.closeQuietly(dos); 160794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao IoUtils.closeQuietly(socket); 161e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 162e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 163794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return true; 164794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 165e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 166e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 167e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao @Override // Binder call 168e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao public boolean clearBcb() { 169e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao if (DEBUG) Slog.d(TAG, "clearBcb"); 170794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao synchronized (sRequestLock) { 171794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return setupOrClearBcb(false, null); 172794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 173e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 174e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 175e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao @Override // Binder call 176e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao public boolean setupBcb(String command) { 177e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]"); 178794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao synchronized (sRequestLock) { 179794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return setupOrClearBcb(true, command); 180794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 181794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 182794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 183794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao @Override // Binder call 184cc76991f37268eed1ef2c978720b32f0c103dc70Tao Bao public void rebootRecoveryWithCommand(String command) { 185794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]"); 186794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao synchronized (sRequestLock) { 187794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (!setupOrClearBcb(true, command)) { 188794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return; 189794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 190794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 191794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao // Having set up the BCB, go ahead and reboot. 192794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 193cc76991f37268eed1ef2c978720b32f0c103dc70Tao Bao pm.reboot(PowerManager.REBOOT_RECOVERY); 194794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 195794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 196794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 197794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao /** 198794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao * Check if any of the init services is still running. If so, we cannot 199794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise 200794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao * it may break the socket communication since init creates / deletes 201794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao * the socket (/dev/socket/uncrypt) on service start / exit. 202794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao */ 203794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao private boolean checkAndWaitForUncryptService() { 204794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { 205794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT); 206794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB); 207794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB); 208794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao final boolean busy = "running".equals(uncryptService) || 209794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao "running".equals(setupBcbService) || "running".equals(clearBcbService); 210794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (DEBUG) { 211794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.i(TAG, "retry: " + retry + " busy: " + busy + 212794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao " uncrypt: [" + uncryptService + "]" + 213794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao " setupBcb: [" + setupBcbService + "]" + 214794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao " clearBcb: [" + clearBcbService + "]"); 215794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 216794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 217794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (!busy) { 218794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return true; 219794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 220794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 221794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao try { 222794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Thread.sleep(1000); 223794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } catch (InterruptedException e) { 224794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.w(TAG, "Interrupted:", e); 225794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 226794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 227794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 228794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return false; 229e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 230e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 231dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao private LocalSocket connectService() { 232dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao LocalSocket socket = new LocalSocket(); 233dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao boolean done = false; 234dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // The uncrypt socket will be created by init upon receiving the 235dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // service request. It may not be ready by this point. So we will 236dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // keep retrying until success or reaching timeout. 237dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { 238dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao try { 239dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET, 240dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao LocalSocketAddress.Namespace.RESERVED)); 241dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao done = true; 242dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao break; 2431284482898712e994d28203d71655f3254b0d4d5Tao Bao } catch (IOException ignored) { 244dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao try { 245dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao Thread.sleep(1000); 246dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } catch (InterruptedException e) { 247794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.w(TAG, "Interrupted:", e); 248dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } 249e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 250e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 251dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao if (!done) { 252dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao Slog.e(TAG, "Timed out connecting to uncrypt socket"); 253dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao return null; 254e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 255dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao return socket; 256dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } 257dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao 258dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao private boolean setupOrClearBcb(boolean isSetup, String command) { 259dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); 260e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 261794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao final boolean available = checkAndWaitForUncryptService(); 262794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao if (!available) { 263794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.e(TAG, "uncrypt service is unavailable."); 264794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao return false; 265794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao } 266794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao 267e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao if (isSetup) { 268e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao SystemProperties.set("ctl.start", "setup-bcb"); 269e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } else { 270e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao SystemProperties.set("ctl.start", "clear-bcb"); 271e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 272e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 273dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // Connect to the uncrypt service socket. 274dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao LocalSocket socket = connectService(); 275dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao if (socket == null) { 276dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao Slog.e(TAG, "Failed to connect to uncrypt socket"); 277dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao return false; 278dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } 279e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 2801284482898712e994d28203d71655f3254b0d4d5Tao Bao DataInputStream dis = null; 2811284482898712e994d28203d71655f3254b0d4d5Tao Bao DataOutputStream dos = null; 2821284482898712e994d28203d71655f3254b0d4d5Tao Bao try { 2831284482898712e994d28203d71655f3254b0d4d5Tao Bao dis = new DataInputStream(socket.getInputStream()); 2841284482898712e994d28203d71655f3254b0d4d5Tao Bao dos = new DataOutputStream(socket.getOutputStream()); 2851284482898712e994d28203d71655f3254b0d4d5Tao Bao 286dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // Send the BCB commands if it's to setup BCB. 287dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao if (isSetup) { 288dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao dos.writeInt(command.length()); 289dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao dos.writeBytes(command); 290dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao dos.flush(); 291e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 292dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao 293dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // Read the status from the socket. 294dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao int status = dis.readInt(); 295dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao 296dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // Ack receipt of the status code. uncrypt waits for the ack so 297dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // the socket won't be destroyed before we receive the code. 298dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao dos.writeInt(0); 299dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao 300dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao if (status == 100) { 301dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") + 302dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao " bcb successfully finished."); 303dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } else { 304dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao // Error in /system/bin/uncrypt. 305dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao Slog.e(TAG, "uncrypt failed with status: " + status); 306dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao return false; 307dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } 308dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } catch (IOException e) { 309794c8b0b3fe16051843c22232d58d6b184dde49bTao Bao Slog.e(TAG, "IOException when communicating with uncrypt:", e); 310e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao return false; 311dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao } finally { 3121284482898712e994d28203d71655f3254b0d4d5Tao Bao IoUtils.closeQuietly(dis); 3131284482898712e994d28203d71655f3254b0d4d5Tao Bao IoUtils.closeQuietly(dos); 314dd3baae7ed9d923c8cb8e832853cbaed01528523Tao Bao IoUtils.closeQuietly(socket); 315e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 316e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao 317e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao return true; 318e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 319e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao } 320e8a403d57c8ea540f8287cdaee8b90f0cf9626a3Tao Bao} 321