Loading services/core/java/com/android/server/RecoverySystemService.java +116 −92 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server; package com.android.server; import android.content.Context; import android.content.Context; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.IRecoverySystem; import android.os.IRecoverySystem; import android.os.IRecoverySystemProgressListener; import android.os.IRecoverySystemProgressListener; import android.os.RecoverySystem; import android.os.RecoverySystem; Loading @@ -26,9 +28,11 @@ import android.system.ErrnoException; import android.system.Os; import android.system.Os; import android.util.Slog; import android.util.Slog; import java.io.BufferedReader; import libcore.io.IoUtils; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.FileWriter; import java.io.IOException; import java.io.IOException; Loading @@ -43,10 +47,10 @@ public final class RecoverySystemService extends SystemService { private static final String TAG = "RecoverySystemService"; private static final String TAG = "RecoverySystemService"; private static final boolean DEBUG = false; private static final boolean DEBUG = false; // A pipe file to monitor the uncrypt progress. // The socket at /dev/socket/uncrypt to communicate with uncrypt. private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status"; private static final String UNCRYPT_SOCKET = "uncrypt"; // Temporary command file to communicate between the system server and uncrypt. private static final String COMMAND_FILE = "/cache/recovery/command"; private static final int SOCKET_CONNECTION_MAX_RETRY = 30; private Context mContext; private Context mContext; Loading Loading @@ -79,27 +83,22 @@ public final class RecoverySystemService extends SystemService { return false; return false; } } // Create the status pipe file to communicate with uncrypt. new File(UNCRYPT_STATUS_FILE).delete(); try { Os.mkfifo(UNCRYPT_STATUS_FILE, 0600); } catch (ErrnoException e) { Slog.e(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE + "\": " + e.getMessage()); return false; } // Trigger uncrypt via init. // Trigger uncrypt via init. SystemProperties.set("ctl.start", "uncrypt"); SystemProperties.set("ctl.start", "uncrypt"); // Read the status from the pipe. // Connect to the uncrypt service socket. try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) { LocalSocket socket = connectService(); if (socket == null) { Slog.e(TAG, "Failed to connect to uncrypt socket"); return false; } // Read the status from the socket. try (DataInputStream dis = new DataInputStream(socket.getInputStream()); DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) { int lastStatus = Integer.MIN_VALUE; int lastStatus = Integer.MIN_VALUE; while (true) { while (true) { String str = reader.readLine(); int status = dis.readInt(); try { int status = Integer.parseInt(str); // Avoid flooding the log with the same message. // Avoid flooding the log with the same message. if (status == lastStatus && lastStatus != Integer.MIN_VALUE) { if (status == lastStatus && lastStatus != Integer.MIN_VALUE) { continue; continue; Loading @@ -118,21 +117,29 @@ public final class RecoverySystemService extends SystemService { } } if (status == 100) { if (status == 100) { Slog.i(TAG, "uncrypt successfully finished."); Slog.i(TAG, "uncrypt successfully finished."); // Ack receipt of the final status code. uncrypt // waits for the ack so the socket won't be // destroyed before we receive the code. dos.writeInt(0); dos.flush(); break; break; } } } else { } else { // Error in /system/bin/uncrypt. // Error in /system/bin/uncrypt. Slog.e(TAG, "uncrypt failed with status: " + status); Slog.e(TAG, "uncrypt failed with status: " + status); return false; // Ack receipt of the final status code. uncrypt waits } // for the ack so the socket won't be destroyed before } catch (NumberFormatException unused) { // we receive the code. Slog.e(TAG, "uncrypt invalid status received: " + str); dos.writeInt(0); dos.flush(); return false; return false; } } } } } catch (IOException unused) { } catch (IOException e) { Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\"."); Slog.e(TAG, "IOException when reading status: " + e); return false; return false; } finally { IoUtils.closeQuietly(socket); } } return true; return true; Loading @@ -150,64 +157,81 @@ public final class RecoverySystemService extends SystemService { return setupOrClearBcb(true, command); return setupOrClearBcb(true, command); } } private LocalSocket connectService() { LocalSocket socket = new LocalSocket(); boolean done = false; // The uncrypt socket will be created by init upon receiving the // service request. It may not be ready by this point. So we will // keep retrying until success or reaching timeout. for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { try { socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET, LocalSocketAddress.Namespace.RESERVED)); done = true; break; } catch (IOException unused) { try { Thread.sleep(1000); } catch (InterruptedException e) { Slog.w(TAG, "Interrupted: " + e); } } } if (!done) { Slog.e(TAG, "Timed out connecting to uncrypt socket"); return null; } return socket; } private boolean setupOrClearBcb(boolean isSetup, String command) { private boolean setupOrClearBcb(boolean isSetup, String command) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); if (isSetup) { if (isSetup) { // Set up the command file to be read by uncrypt. SystemProperties.set("ctl.start", "setup-bcb"); try (FileWriter commandFile = new FileWriter(COMMAND_FILE)) { } else { commandFile.write(command + "\n"); SystemProperties.set("ctl.start", "clear-bcb"); } catch (IOException e) { Slog.e(TAG, "IOException when writing \"" + COMMAND_FILE + "\": " + e.getMessage()); return false; } } } // Create the status pipe file to communicate with uncrypt. // Connect to the uncrypt service socket. new File(UNCRYPT_STATUS_FILE).delete(); LocalSocket socket = connectService(); try { if (socket == null) { Os.mkfifo(UNCRYPT_STATUS_FILE, 0600); Slog.e(TAG, "Failed to connect to uncrypt socket"); } catch (ErrnoException e) { Slog.e(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE + "\": " + e.getMessage()); return false; return false; } } try (DataInputStream dis = new DataInputStream(socket.getInputStream()); DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) { // Send the BCB commands if it's to setup BCB. if (isSetup) { if (isSetup) { SystemProperties.set("ctl.start", "setup-bcb"); dos.writeInt(command.length()); } else { dos.writeBytes(command); SystemProperties.set("ctl.start", "clear-bcb"); dos.flush(); } } // Read the status from the pipe. // Read the status from the socket. try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) { int status = dis.readInt(); while (true) { String str = reader.readLine(); // Ack receipt of the status code. uncrypt waits for the ack so try { // the socket won't be destroyed before we receive the code. int status = Integer.parseInt(str); dos.writeInt(0); dos.flush(); if (status == 100) { if (status == 100) { Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") + Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") + " bcb successfully finished."); " bcb successfully finished."); break; } else { } else { // Error in /system/bin/uncrypt. // Error in /system/bin/uncrypt. Slog.e(TAG, "uncrypt failed with status: " + status); Slog.e(TAG, "uncrypt failed with status: " + status); return false; return false; } } } catch (NumberFormatException unused) { } catch (IOException e) { Slog.e(TAG, "uncrypt invalid status received: " + str); Slog.e(TAG, "IOException when getting output stream: " + e); return false; } } } catch (IOException unused) { Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\"."); return false; return false; } finally { IoUtils.closeQuietly(socket); } } // Delete the command file as we don't need it anymore. new File(COMMAND_FILE).delete(); return true; return true; } } } } Loading Loading
services/core/java/com/android/server/RecoverySystemService.java +116 −92 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server; package com.android.server; import android.content.Context; import android.content.Context; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.IRecoverySystem; import android.os.IRecoverySystem; import android.os.IRecoverySystemProgressListener; import android.os.IRecoverySystemProgressListener; import android.os.RecoverySystem; import android.os.RecoverySystem; Loading @@ -26,9 +28,11 @@ import android.system.ErrnoException; import android.system.Os; import android.system.Os; import android.util.Slog; import android.util.Slog; import java.io.BufferedReader; import libcore.io.IoUtils; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.FileWriter; import java.io.IOException; import java.io.IOException; Loading @@ -43,10 +47,10 @@ public final class RecoverySystemService extends SystemService { private static final String TAG = "RecoverySystemService"; private static final String TAG = "RecoverySystemService"; private static final boolean DEBUG = false; private static final boolean DEBUG = false; // A pipe file to monitor the uncrypt progress. // The socket at /dev/socket/uncrypt to communicate with uncrypt. private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status"; private static final String UNCRYPT_SOCKET = "uncrypt"; // Temporary command file to communicate between the system server and uncrypt. private static final String COMMAND_FILE = "/cache/recovery/command"; private static final int SOCKET_CONNECTION_MAX_RETRY = 30; private Context mContext; private Context mContext; Loading Loading @@ -79,27 +83,22 @@ public final class RecoverySystemService extends SystemService { return false; return false; } } // Create the status pipe file to communicate with uncrypt. new File(UNCRYPT_STATUS_FILE).delete(); try { Os.mkfifo(UNCRYPT_STATUS_FILE, 0600); } catch (ErrnoException e) { Slog.e(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE + "\": " + e.getMessage()); return false; } // Trigger uncrypt via init. // Trigger uncrypt via init. SystemProperties.set("ctl.start", "uncrypt"); SystemProperties.set("ctl.start", "uncrypt"); // Read the status from the pipe. // Connect to the uncrypt service socket. try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) { LocalSocket socket = connectService(); if (socket == null) { Slog.e(TAG, "Failed to connect to uncrypt socket"); return false; } // Read the status from the socket. try (DataInputStream dis = new DataInputStream(socket.getInputStream()); DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) { int lastStatus = Integer.MIN_VALUE; int lastStatus = Integer.MIN_VALUE; while (true) { while (true) { String str = reader.readLine(); int status = dis.readInt(); try { int status = Integer.parseInt(str); // Avoid flooding the log with the same message. // Avoid flooding the log with the same message. if (status == lastStatus && lastStatus != Integer.MIN_VALUE) { if (status == lastStatus && lastStatus != Integer.MIN_VALUE) { continue; continue; Loading @@ -118,21 +117,29 @@ public final class RecoverySystemService extends SystemService { } } if (status == 100) { if (status == 100) { Slog.i(TAG, "uncrypt successfully finished."); Slog.i(TAG, "uncrypt successfully finished."); // Ack receipt of the final status code. uncrypt // waits for the ack so the socket won't be // destroyed before we receive the code. dos.writeInt(0); dos.flush(); break; break; } } } else { } else { // Error in /system/bin/uncrypt. // Error in /system/bin/uncrypt. Slog.e(TAG, "uncrypt failed with status: " + status); Slog.e(TAG, "uncrypt failed with status: " + status); return false; // Ack receipt of the final status code. uncrypt waits } // for the ack so the socket won't be destroyed before } catch (NumberFormatException unused) { // we receive the code. Slog.e(TAG, "uncrypt invalid status received: " + str); dos.writeInt(0); dos.flush(); return false; return false; } } } } } catch (IOException unused) { } catch (IOException e) { Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\"."); Slog.e(TAG, "IOException when reading status: " + e); return false; return false; } finally { IoUtils.closeQuietly(socket); } } return true; return true; Loading @@ -150,64 +157,81 @@ public final class RecoverySystemService extends SystemService { return setupOrClearBcb(true, command); return setupOrClearBcb(true, command); } } private LocalSocket connectService() { LocalSocket socket = new LocalSocket(); boolean done = false; // The uncrypt socket will be created by init upon receiving the // service request. It may not be ready by this point. So we will // keep retrying until success or reaching timeout. for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { try { socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET, LocalSocketAddress.Namespace.RESERVED)); done = true; break; } catch (IOException unused) { try { Thread.sleep(1000); } catch (InterruptedException e) { Slog.w(TAG, "Interrupted: " + e); } } } if (!done) { Slog.e(TAG, "Timed out connecting to uncrypt socket"); return null; } return socket; } private boolean setupOrClearBcb(boolean isSetup, String command) { private boolean setupOrClearBcb(boolean isSetup, String command) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); if (isSetup) { if (isSetup) { // Set up the command file to be read by uncrypt. SystemProperties.set("ctl.start", "setup-bcb"); try (FileWriter commandFile = new FileWriter(COMMAND_FILE)) { } else { commandFile.write(command + "\n"); SystemProperties.set("ctl.start", "clear-bcb"); } catch (IOException e) { Slog.e(TAG, "IOException when writing \"" + COMMAND_FILE + "\": " + e.getMessage()); return false; } } } // Create the status pipe file to communicate with uncrypt. // Connect to the uncrypt service socket. new File(UNCRYPT_STATUS_FILE).delete(); LocalSocket socket = connectService(); try { if (socket == null) { Os.mkfifo(UNCRYPT_STATUS_FILE, 0600); Slog.e(TAG, "Failed to connect to uncrypt socket"); } catch (ErrnoException e) { Slog.e(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE + "\": " + e.getMessage()); return false; return false; } } try (DataInputStream dis = new DataInputStream(socket.getInputStream()); DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) { // Send the BCB commands if it's to setup BCB. if (isSetup) { if (isSetup) { SystemProperties.set("ctl.start", "setup-bcb"); dos.writeInt(command.length()); } else { dos.writeBytes(command); SystemProperties.set("ctl.start", "clear-bcb"); dos.flush(); } } // Read the status from the pipe. // Read the status from the socket. try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) { int status = dis.readInt(); while (true) { String str = reader.readLine(); // Ack receipt of the status code. uncrypt waits for the ack so try { // the socket won't be destroyed before we receive the code. int status = Integer.parseInt(str); dos.writeInt(0); dos.flush(); if (status == 100) { if (status == 100) { Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") + Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") + " bcb successfully finished."); " bcb successfully finished."); break; } else { } else { // Error in /system/bin/uncrypt. // Error in /system/bin/uncrypt. Slog.e(TAG, "uncrypt failed with status: " + status); Slog.e(TAG, "uncrypt failed with status: " + status); return false; return false; } } } catch (NumberFormatException unused) { } catch (IOException e) { Slog.e(TAG, "uncrypt invalid status received: " + str); Slog.e(TAG, "IOException when getting output stream: " + e); return false; } } } catch (IOException unused) { Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\"."); return false; return false; } finally { IoUtils.closeQuietly(socket); } } // Delete the command file as we don't need it anymore. new File(COMMAND_FILE).delete(); return true; return true; } } } } Loading