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