Loading api/test-current.txt +2 −1 Original line number Original line Diff line number Diff line Loading @@ -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(); Loading core/java/android/app/IUiAutomationConnection.aidl +2 −0 Original line number Original line Diff line number Diff line Loading @@ -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); } } core/java/android/app/UiAutomation.java +45 −3 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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]; Loading @@ -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) { Loading @@ -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; } } Loading core/java/android/app/UiAutomationConnection.java +25 −2 Original line number Original line Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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() { Loading @@ -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(); } } }); }); Loading Loading
api/test-current.txt +2 −1 Original line number Original line Diff line number Diff line Loading @@ -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(); Loading
core/java/android/app/IUiAutomationConnection.aidl +2 −0 Original line number Original line Diff line number Diff line Loading @@ -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); } }
core/java/android/app/UiAutomation.java +45 −3 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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]; Loading @@ -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) { Loading @@ -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; } } Loading
core/java/android/app/UiAutomationConnection.java +25 −2 Original line number Original line Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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() { Loading @@ -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(); } } }); }); Loading