Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c50a911d authored by Eugene Susla's avatar Eugene Susla Committed by Android (Google) Code Review
Browse files

Merge "Run shell commands reliably"

parents 098991b9 8fa2bdb0
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -537,7 +537,8 @@ package android.app {


  public final class UiAutomation {
  public final class UiAutomation {
    method public void destroy();
    method public void destroy();
    method public android.os.ParcelFileDescriptor[] executeShellCommandRw(String);
    method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRw(@NonNull String);
    method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRwe(@NonNull String);
    method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
    method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
    method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
    method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
    method public void syncInputTransactions();
    method public void syncInputTransactions();
+2 −0
Original line number Original line Diff line number Diff line
@@ -52,4 +52,6 @@ interface IUiAutomationConnection {
    void dropShellPermissionIdentity();
    void dropShellPermissionIdentity();
    // Called from the system process.
    // Called from the system process.
    oneway void shutdown();
    oneway void shutdown();
    void executeShellCommandWithStderr(String command, in ParcelFileDescriptor sink,
                in ParcelFileDescriptor source, in ParcelFileDescriptor stderrSink);
}
}
+45 −3
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import android.accessibilityservice.IAccessibilityServiceConnection;
import android.annotation.IntDef;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
import android.graphics.Bitmap;
@@ -1245,7 +1246,34 @@ public final class UiAutomation {
     * @hide
     * @hide
     */
     */
    @TestApi
    @TestApi
    public ParcelFileDescriptor[] executeShellCommandRw(String command) {
    public @NonNull ParcelFileDescriptor[] executeShellCommandRw(@NonNull String command) {
        return executeShellCommandInternal(command, false /* includeStderr */);
    }

    /**
     * Executes a shell command. This method returns three file descriptors,
     * one that points to the standard output stream (element at index 0), one that points
     * to the standard input stream (element at index 1), and one points to
     * standard error stream (element at index 2). The command execution is similar
     * to running "adb shell <command>" from a host connected to the device.
     * <p>
     * <strong>Note:</strong> It is your responsibility to close the returned file
     * descriptors once you are done reading/writing.
     * </p>
     *
     * @param command The command to execute.
     * @return File descriptors (out, in, err) to the standard output/input/error streams.
     *
     * @hide
     */
    @TestApi
    @SuppressLint("ArrayReturn") // For consistency with other APIs
    public @NonNull ParcelFileDescriptor[] executeShellCommandRwe(@NonNull String command) {
        return executeShellCommandInternal(command, true /* includeStderr */);
    }

    private ParcelFileDescriptor[] executeShellCommandInternal(
            String command, boolean includeStderr) {
        warnIfBetterCommand(command);
        warnIfBetterCommand(command);


        ParcelFileDescriptor source_read = null;
        ParcelFileDescriptor source_read = null;
@@ -1254,6 +1282,9 @@ public final class UiAutomation {
        ParcelFileDescriptor source_write = null;
        ParcelFileDescriptor source_write = null;
        ParcelFileDescriptor sink_write = null;
        ParcelFileDescriptor sink_write = null;


        ParcelFileDescriptor stderr_source_read = null;
        ParcelFileDescriptor stderr_sink_read = null;

        try {
        try {
            ParcelFileDescriptor[] pipe_read = ParcelFileDescriptor.createPipe();
            ParcelFileDescriptor[] pipe_read = ParcelFileDescriptor.createPipe();
            source_read = pipe_read[0];
            source_read = pipe_read[0];
@@ -1263,8 +1294,15 @@ public final class UiAutomation {
            source_write = pipe_write[0];
            source_write = pipe_write[0];
            sink_write = pipe_write[1];
            sink_write = pipe_write[1];


            if (includeStderr) {
                ParcelFileDescriptor[] stderr_read = ParcelFileDescriptor.createPipe();
                stderr_source_read = stderr_read[0];
                stderr_sink_read = stderr_read[1];
            }

            // Calling out without a lock held.
            // Calling out without a lock held.
            mUiAutomationConnection.executeShellCommand(command, sink_read, source_write);
            mUiAutomationConnection.executeShellCommandWithStderr(
                    command, sink_read, source_write, stderr_sink_read);
        } catch (IOException ioe) {
        } catch (IOException ioe) {
            Log.e(LOG_TAG, "Error executing shell command!", ioe);
            Log.e(LOG_TAG, "Error executing shell command!", ioe);
        } catch (RemoteException re) {
        } catch (RemoteException re) {
@@ -1272,11 +1310,15 @@ public final class UiAutomation {
        } finally {
        } finally {
            IoUtils.closeQuietly(sink_read);
            IoUtils.closeQuietly(sink_read);
            IoUtils.closeQuietly(source_write);
            IoUtils.closeQuietly(source_write);
            IoUtils.closeQuietly(stderr_sink_read);
        }
        }


        ParcelFileDescriptor[] result = new ParcelFileDescriptor[2];
        ParcelFileDescriptor[] result = new ParcelFileDescriptor[includeStderr ? 3 : 2];
        result[0] = source_read;
        result[0] = source_read;
        result[1] = sink_write;
        result[1] = sink_write;
        if (includeStderr) {
            result[2] = stderr_source_read;
        }
        return result;
        return result;
    }
    }


+25 −2
Original line number Original line Diff line number Diff line
@@ -372,6 +372,13 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
    @Override
    @Override
    public void executeShellCommand(final String command, final ParcelFileDescriptor sink,
    public void executeShellCommand(final String command, final ParcelFileDescriptor sink,
            final ParcelFileDescriptor source) throws RemoteException {
            final ParcelFileDescriptor source) throws RemoteException {
        executeShellCommandWithStderr(command, sink, source, null /* stderrSink */);
    }

    @Override
    public void executeShellCommandWithStderr(final String command, final ParcelFileDescriptor sink,
            final ParcelFileDescriptor source, final ParcelFileDescriptor stderrSink)
            throws RemoteException {
        synchronized (mLock) {
        synchronized (mLock) {
            throwIfCalledByNotTrustedUidLocked();
            throwIfCalledByNotTrustedUidLocked();
            throwIfShutdownLocked();
            throwIfShutdownLocked();
@@ -409,6 +416,18 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
            writeToProcess = null;
            writeToProcess = null;
        }
        }


        // Read from process stderr and write to pipe
        final Thread readStderrFromProcess;
        if (stderrSink != null) {
            InputStream sink_in = process.getErrorStream();
            OutputStream sink_out = new FileOutputStream(stderrSink.getFileDescriptor());

            readStderrFromProcess = new Thread(new Repeater(sink_in, sink_out));
            readStderrFromProcess.start();
        } else {
            readStderrFromProcess = null;
        }

        Thread cleanup = new Thread(new Runnable() {
        Thread cleanup = new Thread(new Runnable() {
            @Override
            @Override
            public void run() {
            public void run() {
@@ -419,11 +438,15 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
                    if (readFromProcess != null) {
                    if (readFromProcess != null) {
                        readFromProcess.join();
                        readFromProcess.join();
                    }
                    }
                    if (readStderrFromProcess != null) {
                        readStderrFromProcess.join();
                    }
                } catch (InterruptedException exc) {
                } catch (InterruptedException exc) {
                    Log.e(TAG, "At least one of the threads was interrupted");
                    Log.e(TAG, "At least one of the threads was interrupted");
                }
                }
                IoUtils.closeQuietly(sink);
                IoUtils.closeQuietly(sink);
                IoUtils.closeQuietly(source);
                IoUtils.closeQuietly(source);
                IoUtils.closeQuietly(stderrSink);
                process.destroy();
                process.destroy();
            }
            }
        });
        });