1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.tradefed.device;
17 
18 import com.android.ddmlib.IDevice;
19 import com.android.ddmlib.IShellOutputReceiver;
20 import com.android.ddmlib.Log.LogLevel;
21 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
22 import com.android.tradefed.build.IBuildInfo;
23 import com.android.tradefed.command.remote.DeviceDescriptor;
24 import com.android.tradefed.device.ITestDevice.MountPointInfo;
25 import com.android.tradefed.device.ITestDevice.RecoveryMode;
26 import com.android.tradefed.log.ITestLogger;
27 import com.android.tradefed.result.ITestLifeCycleReceiver;
28 import com.android.tradefed.result.InputStreamSource;
29 import com.android.tradefed.targetprep.TargetSetupError;
30 import com.android.tradefed.util.Bugreport;
31 import com.android.tradefed.util.CommandResult;
32 import com.android.tradefed.util.ProcessInfo;
33 import com.android.tradefed.util.TimeUtil;
34 
35 import com.google.errorprone.annotations.MustBeClosed;
36 
37 import java.io.File;
38 import java.io.InputStream;
39 import java.util.Collection;
40 import java.util.Date;
41 import java.util.List;
42 import java.util.concurrent.TimeUnit;
43 
44 /**
45  * Provides an reliable and slightly higher level API to a ddmlib {@link IDevice}.
46  * <p/>
47  * Retries device commands for a configurable amount, and provides a device recovery
48  * interface for devices which are unresponsive.
49  */
50 public interface INativeDevice {
51 
52     /**
53      * Default value when API Level cannot be detected
54      */
55     public final static int UNKNOWN_API_LEVEL = -1;
56 
57     /**
58      * Set the {@link TestDeviceOptions} for the device
59      */
setOptions(TestDeviceOptions options)60     public void setOptions(TestDeviceOptions options);
61 
62     /**
63      * Returns a reference to the associated ddmlib {@link IDevice}.
64      * <p/>
65      * A new {@link IDevice} may be allocated by DDMS each time the device disconnects and
66      * reconnects from adb. Thus callers should not keep a reference to the {@link IDevice},
67      * because that reference may become stale.
68      *
69      * @return the {@link IDevice}
70      */
getIDevice()71     public IDevice getIDevice();
72 
73     /**
74      * Convenience method to get serial number of this device.
75      *
76      * @return the {@link String} serial number
77      */
getSerialNumber()78     public String getSerialNumber();
79 
80     /**
81      * Retrieve the given property value from the device.
82      *
83      * @param name the property name
84      * @return the property value or <code>null</code> if it does not exist
85      * @throws DeviceNotAvailableException
86      */
getProperty(String name)87     public String getProperty(String name) throws DeviceNotAvailableException;
88 
89     /**
90      * Convenience method to get the bootloader version of this device.
91      * <p/>
92      * Will attempt to retrieve bootloader version from the device's current state. (ie if device
93      * is in fastboot mode, it will attempt to retrieve version from fastboot)
94      *
95      * @return the {@link String} bootloader version or <code>null</code> if it cannot be found
96      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
97      *             recovered.
98      */
getBootloaderVersion()99     public String getBootloaderVersion() throws DeviceNotAvailableException;
100 
101     /**
102      * Convenience method to get baseband (radio) version of this device. Getting the radio version
103      * is device specific, so it might not return the correct information for all devices. This
104      * method relies on the gsm.version.baseband propery to return the correct version information.
105      * This is not accurate for some CDMA devices and the version returned here might not match
106      * the version reported from fastboot and might not return the version for the CDMA radio.
107      * TL;DR this method only reports accurate version if the gsm.version.baseband property is the
108      * same as the version returned by <code>fastboot getvar version-baseband</code>.
109      *
110      * @return the {@link String} baseband version or <code>null</code> if it cannot be determined
111      *          (device has no radio or version string cannot be read)
112      * @throws DeviceNotAvailableException if the connection with the device is lost and cannot
113      *          be recovered.
114      */
getBasebandVersion()115     public String getBasebandVersion() throws DeviceNotAvailableException;
116 
117     /**
118      * Convenience method to get the product type of this device.
119      * <p/>
120      * This method will work if device is in either adb or fastboot mode.
121      *
122      * @return the {@link String} product type name. Will not be null
123      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
124      *             recovered, or if product type can not be determined
125      */
getProductType()126     public String getProductType() throws DeviceNotAvailableException;
127 
128     /**
129      * Convenience method to get the product variant of this device.
130      * <p/>
131      * This method will work if device is in either adb or fastboot mode.
132      *
133      * @return the {@link String} product variant name or <code>null</code> if it cannot be
134      *         determined
135      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
136      *             recovered.
137      */
getProductVariant()138     public String getProductVariant() throws DeviceNotAvailableException;
139 
140     /**
141      * Convenience method to get the product type of this device when its in fastboot mode.
142      * <p/>
143      * This method should only be used if device should be in fastboot. Its a bit safer variant
144      * than the generic {@link #getProductType()} method in this case, because ITestDevice
145      * will know to recover device into fastboot if device is in incorrect state or is
146      * unresponsive.
147      *
148      * @return the {@link String} product type name or <code>null</code> if it cannot be determined
149      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
150      *             recovered.
151      */
getFastbootProductType()152     public String getFastbootProductType() throws DeviceNotAvailableException;
153 
154     /**
155      * Convenience method to get the product type of this device when its in fastboot mode.
156      * <p/>
157      * This method should only be used if device should be in fastboot. Its a bit safer variant
158      * than the generic {@link #getProductType()} method in this case, because ITestDevice
159      * will know to recover device into fastboot if device is in incorrect state or is
160      * unresponsive.
161      *
162      * @return the {@link String} product type name or <code>null</code> if it cannot be determined
163      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
164      *             recovered.
165      */
getFastbootProductVariant()166     public String getFastbootProductVariant() throws DeviceNotAvailableException;
167 
168     /**
169      * Retrieve the alias of the build that the device is currently running.
170      *
171      * <p>Build alias is usually a more readable string than build id (typically a number for
172      * Nexus builds). For example, final Android 4.2 release has build alias JDQ39, and build id
173      * 573038
174      * @return the build alias or fall back to build id if it could not be retrieved
175      * @throws DeviceNotAvailableException
176      */
getBuildAlias()177     public String getBuildAlias() throws DeviceNotAvailableException;
178 
179     /**
180      * Retrieve the build the device is currently running.
181      *
182      * @return the build id or {@link IBuildInfo#UNKNOWN_BUILD_ID} if it could not be retrieved
183      * @throws DeviceNotAvailableException
184      */
getBuildId()185     public String getBuildId() throws DeviceNotAvailableException;
186 
187     /**
188      * Retrieve the build flavor for the device.
189      *
190      * @return the build flavor or null if it could not be retrieved
191      * @throws DeviceNotAvailableException
192      */
getBuildFlavor()193     public String getBuildFlavor() throws DeviceNotAvailableException;
194 
195     /**
196      * Executes the given adb shell command, retrying multiple times if command fails.
197      * <p/>
198      * A simpler form of
199      * {@link #executeShellCommand(String, IShellOutputReceiver, long, TimeUnit, int)} with
200      * default values.
201      *
202      * @param command the adb shell command to run
203      * @param receiver the {@link IShellOutputReceiver} to direct shell output to.
204      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
205      *             recovered.
206      */
executeShellCommand(String command, IShellOutputReceiver receiver)207     public void executeShellCommand(String command, IShellOutputReceiver receiver)
208         throws DeviceNotAvailableException;
209 
210     /**
211      * Executes a adb shell command, with more parameters to control command behavior.
212      *
213      * @see #executeShellCommand(String, IShellOutputReceiver)
214      * @param command the adb shell command to run
215      * @param receiver the {@link IShellOutputReceiver} to direct shell output to.
216      * @param maxTimeToOutputShellResponse the maximum amount of time during which the command is
217      *            allowed to not output any response; unit as specified in <code>timeUnit</code>
218      * @param timeUnit unit for <code>maxTimeToOutputShellResponse</code>
219      * @param retryAttempts the maximum number of times to retry command if it fails due to a
220      *            exception. DeviceNotResponsiveException will be thrown if <var>retryAttempts</var>
221      *            are performed without success.
222      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
223      *             recovered.
224      * @see TimeUtil
225      */
executeShellCommand(String command, IShellOutputReceiver receiver, long maxTimeToOutputShellResponse, TimeUnit timeUnit, int retryAttempts)226     public void executeShellCommand(String command, IShellOutputReceiver receiver,
227             long maxTimeToOutputShellResponse, TimeUnit timeUnit, int retryAttempts)
228                     throws DeviceNotAvailableException;
229 
230     /**
231      * Executes a adb shell command, with more parameters to control command behavior.
232      *
233      * @see #executeShellCommand(String, IShellOutputReceiver)
234      * @param command the adb shell command to run
235      * @param receiver the {@link IShellOutputReceiver} to direct shell output to.
236      * @param maxTimeoutForCommand the maximum timeout for the command to complete; unit as
237      *     specified in <code>timeUnit</code>
238      * @param maxTimeToOutputShellResponse the maximum amount of time during which the command is
239      *     allowed to not output any response; unit as specified in <code>timeUnit</code>
240      * @param timeUnit unit for <code>maxTimeToOutputShellResponse</code>
241      * @param retryAttempts the maximum number of times to retry command if it fails due to a
242      *     exception. DeviceNotResponsiveException will be thrown if <var>retryAttempts</var> are
243      *     performed without success.
244      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
245      *     recovered.
246      * @see TimeUtil
247      */
executeShellCommand( String command, IShellOutputReceiver receiver, long maxTimeoutForCommand, long maxTimeToOutputShellResponse, TimeUnit timeUnit, int retryAttempts)248     public void executeShellCommand(
249             String command,
250             IShellOutputReceiver receiver,
251             long maxTimeoutForCommand,
252             long maxTimeToOutputShellResponse,
253             TimeUnit timeUnit,
254             int retryAttempts)
255             throws DeviceNotAvailableException;
256 
257     /**
258      * Helper method which executes a adb shell command and returns output as a {@link String}.
259      *
260      * @param command the adb shell command to run
261      * @return the shell output
262      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
263      * recovered.
264      */
executeShellCommand(String command)265     public String executeShellCommand(String command) throws DeviceNotAvailableException;
266 
267     /**
268      * Helper method which executes a adb shell command and returns the results as a {@link
269      * CommandResult} properly populated with the command status output, stdout and stderr.
270      *
271      * @param command The command that should be run.
272      * @return The result in {@link CommandResult}.
273      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
274      *     recovered.
275      */
executeShellV2Command(String command)276     public CommandResult executeShellV2Command(String command) throws DeviceNotAvailableException;
277 
278     /**
279      * Executes a adb shell command, with more parameters to control command behavior.
280      *
281      * @see #executeShellV2Command(String)
282      * @param command the adb shell command to run
283      * @param maxTimeoutForCommand the maximum timeout for the command to complete; unit as
284      *     specified in <code>timeUnit</code>
285      * @param timeUnit unit for <code>maxTimeToOutputShellResponse</code>
286      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
287      *     recovered.
288      * @see TimeUtil
289      */
executeShellV2Command( String command, final long maxTimeoutForCommand, final TimeUnit timeUnit)290     public CommandResult executeShellV2Command(
291             String command, final long maxTimeoutForCommand, final TimeUnit timeUnit)
292             throws DeviceNotAvailableException;
293 
294     /**
295      * Executes a adb shell command, with more parameters to control command behavior.
296      *
297      * @see #executeShellV2Command(String)
298      * @param command the adb shell command to run
299      * @param maxTimeoutForCommand the maximum timeout for the command to complete; unit as
300      *     specified in <code>timeUnit</code>
301      * @param timeUnit unit for <code>maxTimeToOutputShellResponse</code>
302      * @param retryAttempts the maximum number of times to retry command if it fails due to a
303      *     exception. DeviceNotResponsiveException will be thrown if <var>retryAttempts</var> are
304      *     performed without success.
305      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
306      *     recovered.
307      * @see TimeUtil
308      */
executeShellV2Command( String command, final long maxTimeoutForCommand, final TimeUnit timeUnit, int retryAttempts)309     public CommandResult executeShellV2Command(
310             String command,
311             final long maxTimeoutForCommand,
312             final TimeUnit timeUnit,
313             int retryAttempts)
314             throws DeviceNotAvailableException;
315 
316     /**
317      * Helper method which executes a adb command as a system command.
318      * <p/>
319      * {@link #executeShellCommand(String)} should be used instead wherever possible, as that
320      * method provides better failure detection and performance.
321      *
322      * @param commandArgs the adb command and arguments to run
323      * @return the stdout from command. <code>null</code> if command failed to execute.
324      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
325      * recovered.
326      */
executeAdbCommand(String... commandArgs)327     public String executeAdbCommand(String... commandArgs) throws DeviceNotAvailableException;
328 
329     /**
330      * Helper method which executes a fastboot command as a system command with a default timeout
331      * of 2 minutes.
332      * <p/>
333      * Expected to be used when device is already in fastboot mode.
334      *
335      * @param commandArgs the fastboot command and arguments to run
336      * @return the CommandResult containing output of command
337      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
338      * recovered.
339      */
executeFastbootCommand(String... commandArgs)340     public CommandResult executeFastbootCommand(String... commandArgs)
341             throws DeviceNotAvailableException;
342 
343     /**
344      * Helper method which executes a fastboot command as a system command.
345      * <p/>
346      * Expected to be used when device is already in fastboot mode.
347      *
348      * @param timeout the time in milliseconds before the command expire
349      * @param commandArgs the fastboot command and arguments to run
350      * @return the CommandResult containing output of command
351      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
352      * recovered.
353      */
executeFastbootCommand(long timeout, String... commandArgs)354     public CommandResult executeFastbootCommand(long timeout, String... commandArgs)
355             throws DeviceNotAvailableException;
356 
357     /**
358      * Helper method which executes a long running fastboot command as a system command.
359      * <p/>
360      * Identical to {@link #executeFastbootCommand(String...)} except uses a longer timeout.
361      *
362      * @param commandArgs the fastboot command and arguments to run
363      * @return the CommandResult containing output of command
364      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
365      * recovered.
366      */
executeLongFastbootCommand(String... commandArgs)367     public CommandResult executeLongFastbootCommand(String... commandArgs)
368             throws DeviceNotAvailableException;
369 
370     /**
371      * Get whether to use fastboot erase or fastboot format to wipe a partition on the device.
372      *
373      * @return {@code true} if fastboot erase will be used or {@code false} if fastboot format will
374      * be used.
375      * @see #fastbootWipePartition(String)
376      */
getUseFastbootErase()377     public boolean getUseFastbootErase();
378 
379     /**
380      * Set whether to use fastboot erase or fastboot format to wipe a partition on the device.
381      *
382      * @param useFastbootErase {@code true} if fastboot erase should be used or {@code false} if
383      * fastboot format should be used.
384      * @see #fastbootWipePartition(String)
385      */
setUseFastbootErase(boolean useFastbootErase)386     public void setUseFastbootErase(boolean useFastbootErase);
387 
388     /**
389      * Helper method which wipes a partition for the device.
390      * <p/>
391      * If {@link #getUseFastbootErase()} is {@code true}, then fastboot erase will be used to wipe
392      * the partition. The device must then create a filesystem the next time the device boots.
393      * Otherwise, fastboot format is used which will create a new filesystem on the device.
394      * <p/>
395      * Expected to be used when device is already in fastboot mode.
396      *
397      * @param partition the partition to wipe
398      * @return the CommandResult containing output of command
399      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
400      * recovered.
401      */
fastbootWipePartition(String partition)402     public CommandResult fastbootWipePartition(String partition) throws DeviceNotAvailableException;
403 
404     /**
405      * Runs instrumentation tests, and provides device recovery.
406      *
407      * <p>If connection with device is lost before test run completes, and recovery succeeds, all
408      * listeners will be informed of testRunFailed and "false" will be returned. The test command
409      * will not be rerun. It is left to callers to retry if necessary.
410      *
411      * <p>If connection with device is lost before test run completes, and recovery fails, all
412      * listeners will be informed of testRunFailed and DeviceNotAvailableException will be thrown.
413      *
414      * @param runner the {@link IRemoteAndroidTestRunner} which runs the tests
415      * @param listeners the test result listeners
416      * @return <code>true</code> if test command completed. <code>false</code> if it failed to
417      *     complete due to device communication exception, but recovery succeeded
418      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
419      *     recovered. ie test command failed to complete and recovery failed.
420      */
runInstrumentationTests( IRemoteAndroidTestRunner runner, Collection<ITestLifeCycleReceiver> listeners)421     public boolean runInstrumentationTests(
422             IRemoteAndroidTestRunner runner, Collection<ITestLifeCycleReceiver> listeners)
423             throws DeviceNotAvailableException;
424 
425     /**
426      * Convenience method for performing {@link #runInstrumentationTests(IRemoteAndroidTestRunner,
427      * Collection)} with one or more listeners passed as parameters.
428      *
429      * @param runner the {@link IRemoteAndroidTestRunner} which runs the tests
430      * @param listeners the test result listener(s)
431      * @return <code>true</code> if test command completed. <code>false</code> if it failed to
432      *     complete, but recovery succeeded
433      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
434      *     recovered. ie test command failed to complete and recovery failed.
435      */
runInstrumentationTests( IRemoteAndroidTestRunner runner, ITestLifeCycleReceiver... listeners)436     public boolean runInstrumentationTests(
437             IRemoteAndroidTestRunner runner, ITestLifeCycleReceiver... listeners)
438             throws DeviceNotAvailableException;
439 
440     /**
441      * Same as {@link ITestDevice#runInstrumentationTests(IRemoteAndroidTestRunner, Collection)} but
442      * runs the test for the given user.
443      */
runInstrumentationTestsAsUser( IRemoteAndroidTestRunner runner, int userId, Collection<ITestLifeCycleReceiver> listeners)444     public boolean runInstrumentationTestsAsUser(
445             IRemoteAndroidTestRunner runner,
446             int userId,
447             Collection<ITestLifeCycleReceiver> listeners)
448             throws DeviceNotAvailableException;
449 
450     /**
451      * Same as {@link ITestDevice#runInstrumentationTests(IRemoteAndroidTestRunner,
452      * ITestLifeCycleReceiver...)} but runs the test for a given user.
453      */
runInstrumentationTestsAsUser( IRemoteAndroidTestRunner runner, int userId, ITestLifeCycleReceiver... listeners)454     public boolean runInstrumentationTestsAsUser(
455             IRemoteAndroidTestRunner runner, int userId, ITestLifeCycleReceiver... listeners)
456             throws DeviceNotAvailableException;
457 
458     /**
459      * Check whether platform on device supports runtime permission granting
460      * @return True if runtime permission are supported, false otherwise.
461      * @throws DeviceNotAvailableException
462      */
isRuntimePermissionSupported()463     public boolean isRuntimePermissionSupported() throws DeviceNotAvailableException;
464 
465     /**
466      * Retrieves a file off device.
467      *
468      * @param remoteFilePath the absolute path to file on device.
469      * @param localFile the local file to store contents in. If non-empty, contents will be
470      *            replaced.
471      * @return <code>true</code> if file was retrieved successfully. <code>false</code> otherwise.
472      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
473      *             recovered.
474      */
pullFile(String remoteFilePath, File localFile)475     public boolean pullFile(String remoteFilePath, File localFile)
476             throws DeviceNotAvailableException;
477 
478     /**
479      * Retrieves a file off device, stores it in a local temporary {@link File}, and returns that
480      * {@code File}.
481      *
482      * @param remoteFilePath the absolute path to file on device.
483      * @return A {@link File} containing the contents of the device file, or {@code null} if the
484      *         copy failed for any reason (including problems with the host filesystem)
485      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
486      *             recovered.
487      */
pullFile(String remoteFilePath)488     public File pullFile(String remoteFilePath) throws DeviceNotAvailableException;
489 
490     /**
491      * Retrieves a file off device, and returns the contents.
492      *
493      * @param remoteFilePath the absolute path to file on device.
494      * @return A {@link String} containing the contents of the device file, or {@code null} if the
495      *         copy failed for any reason (including problems with the host filesystem)
496      */
pullFileContents(String remoteFilePath)497     public String pullFileContents(String remoteFilePath) throws DeviceNotAvailableException;
498 
499     /**
500      * A convenience method to retrieve a file from the device's external storage, stores it in a
501      * local temporary {@link File}, and return a reference to that {@code File}.
502      *
503      * @param remoteFilePath the path to file on device, relative to the device's external storage
504      *        mountpoint
505      * @return A {@link File} containing the contents of the device file, or {@code null} if the
506      *         copy failed for any reason (including problems with the host filesystem)
507      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
508      *             recovered.
509      */
pullFileFromExternal(String remoteFilePath)510     public File pullFileFromExternal(String remoteFilePath) throws DeviceNotAvailableException;
511 
512     /**
513      * Recursively pull directory contents from device.
514      *
515      * @param deviceFilePath the absolute file path of the remote source
516      * @param localDir the local directory to pull files into
517      * @return <code>true</code> if file was pulled successfully. <code>false</code> otherwise.
518      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
519      * recovered.
520      */
pullDir(String deviceFilePath, File localDir)521     public boolean pullDir(String deviceFilePath, File localDir)
522             throws DeviceNotAvailableException;
523 
524     /**
525      * Push a file to device
526      *
527      * @param localFile the local file to push
528      * @param deviceFilePath the remote destination absolute file path
529      * @return <code>true</code> if file was pushed successfully. <code>false</code> otherwise.
530      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
531      * recovered.
532      */
pushFile(File localFile, String deviceFilePath)533     public boolean pushFile(File localFile, String deviceFilePath)
534             throws DeviceNotAvailableException;
535 
536     /**
537      * Push file created from a string to device
538      *
539      * @param contents the contents of the file to push
540      * @param deviceFilePath the remote destination absolute file path
541      * @return <code>true</code> if string was pushed successfully. <code>false</code> otherwise.
542      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
543      * recovered.
544      */
pushString(String contents, String deviceFilePath)545     public boolean pushString(String contents, String deviceFilePath)
546             throws DeviceNotAvailableException;
547 
548     /**
549      * Recursively push directory contents to device.
550      *
551      * @param localDir the local directory to push
552      * @param deviceFilePath the absolute file path of the remote destination
553      * @return <code>true</code> if file was pushed successfully. <code>false</code> otherwise.
554      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
555      * recovered.
556      */
pushDir(File localDir, String deviceFilePath)557     public boolean pushDir(File localDir, String deviceFilePath)
558             throws DeviceNotAvailableException;
559 
560     /**
561      * Incrementally syncs the contents of a local file directory to device.
562      * <p/>
563      * Decides which files to push by comparing timestamps of local files with their remote
564      * equivalents. Only 'newer' or non-existent files will be pushed to device. Thus overhead
565      * should be relatively small if file set on device is already up to date.
566      * <p/>
567      * Hidden files (with names starting with ".") will be ignored.
568      * <p/>
569      * Example usage: syncFiles("/tmp/files", "/sdcard") will created a /sdcard/files directory if
570      * it doesn't already exist, and recursively push the /tmp/files contents to /sdcard/files.
571      *
572      * @param localFileDir the local file directory containing files to recursively push.
573      * @param deviceFilePath the remote destination absolute file path root. All directories in thos
574      *            file path must be readable. ie pushing to /data/local/tmp when adb is not root
575      *            will fail
576      * @return <code>true</code> if files were synced successfully. <code>false</code> otherwise.
577      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
578      *             recovered.
579      */
syncFiles(File localFileDir, String deviceFilePath)580     public boolean syncFiles(File localFileDir, String deviceFilePath)
581             throws DeviceNotAvailableException;
582 
583     /**
584      * Helper method to determine if file on device exists.
585      *
586      * @param deviceFilePath the absolute path of file on device to check
587      * @return <code>true</code> if file exists, <code>false</code> otherwise.
588      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
589      * recovered.
590      */
doesFileExist(String deviceFilePath)591     public boolean doesFileExist(String deviceFilePath) throws DeviceNotAvailableException;
592 
593     /**
594      * Retrieve a reference to a remote file on device.
595      *
596      * @param path the file path to retrieve. Can be an absolute path or path relative to '/'. (ie
597      *            both "/system" and "system" syntax is supported)
598      * @return the {@link IFileEntry} or <code>null</code> if file at given <var>path</var> cannot
599      *         be found
600      * @throws DeviceNotAvailableException
601      */
getFileEntry(String path)602     public IFileEntry getFileEntry(String path) throws DeviceNotAvailableException;
603 
604     /**
605      * Return True if the path on the device is a directory, false otherwise.
606      *
607      * @throws DeviceNotAvailableException
608      */
isDirectory(String deviceFilePath)609     public boolean isDirectory(String deviceFilePath) throws DeviceNotAvailableException;
610 
611     /**
612      * Alternative to using {@link IFileEntry} that sometimes won't work because of permissions.
613      *
614      * @param deviceFilePath is the path on the device where to do the search
615      * @return Array of string containing all the file in a path on the device.
616      * @throws DeviceNotAvailableException
617      */
getChildren(String deviceFilePath)618     public String[] getChildren(String deviceFilePath) throws DeviceNotAvailableException;
619 
620     /**
621      * Helper method to determine amount of free space on device external storage.
622      *
623      * @return the amount of free space in KB
624      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
625      * recovered.
626      */
getExternalStoreFreeSpace()627     public long getExternalStoreFreeSpace() throws DeviceNotAvailableException;
628 
629     /**
630      * Helper method to determine amount of free space on device partition.
631      *
632      * @return the amount of free space in KB
633      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
634      *     recovered.
635      */
getPartitionFreeSpace(String partition)636     public long getPartitionFreeSpace(String partition) throws DeviceNotAvailableException;
637 
638     /**
639      * Returns a mount point.
640      * <p/>
641      * Queries the device directly if the cached info in {@link IDevice} is not available.
642      * <p/>
643      * TODO: move this behavior to {@link IDevice#getMountPoint(String)}
644      *
645      * @param mountName the name of the mount point
646      * @return the mount point or <code>null</code>
647      * @see IDevice#getMountPoint(String)
648      */
getMountPoint(String mountName)649     public String getMountPoint(String mountName);
650 
651     /**
652      * Returns a parsed version of the information in /proc/mounts on the device
653      *
654      * @return A {@link List} of {@link MountPointInfo} containing the information in "/proc/mounts"
655      */
getMountPointInfo()656     public List<MountPointInfo> getMountPointInfo() throws DeviceNotAvailableException;
657 
658     /**
659      * Returns a {@link MountPointInfo} corresponding to the specified mountpoint path, or
660      * <code>null</code> if that path has nothing mounted or otherwise does not appear in
661      * /proc/mounts as a mountpoint.
662      *
663      * @return A {@link List} of {@link MountPointInfo} containing the information in "/proc/mounts"
664      * @see #getMountPointInfo()
665      */
getMountPointInfo(String mountpoint)666     public MountPointInfo getMountPointInfo(String mountpoint) throws DeviceNotAvailableException;
667 
668     /**
669      * Start capturing logcat output from device in the background.
670      * <p/>
671      * Will have no effect if logcat output is already being captured.
672      * Data can be later retrieved via getLogcat.
673      * <p/>
674      * When the device is no longer in use, {@link #stopLogcat()} must be called.
675      * <p/>
676      * {@link #startLogcat()} and {@link #stopLogcat()} do not normally need to be called when
677      * within a TF invocation context, as the TF framework will start and stop logcat.
678      */
startLogcat()679     public void startLogcat();
680 
681     /**
682      * Stop capturing logcat output from device, and discard currently saved logcat data.
683      * <p/>
684      * Will have no effect if logcat output is not being captured.
685      */
stopLogcat()686     public void stopLogcat();
687 
688     /**
689      * Deletes any accumulated logcat data.
690      * <p/>
691      * This is useful for cases when you want to ensure {@link ITestDevice#getLogcat()} only returns
692      * log data produced after a certain point (such as after flashing a new device build, etc).
693      */
clearLogcat()694     public void clearLogcat();
695 
696     /**
697      * Grabs a snapshot stream of the logcat data.
698      *
699      * <p>Works in two modes:
700      * <li>If the logcat is currently being captured in the background, will return up to {@link
701      *     TestDeviceOptions#getMaxLogcatDataSize()} bytes of the current contents of the background
702      *     logcat capture
703      * <li>Otherwise, will return a static dump of the logcat data if device is currently responding
704      */
705     @MustBeClosed
getLogcat()706     public InputStreamSource getLogcat();
707 
708     /**
709      * Grabs a snapshot stream of captured logcat data starting the date provided. The time on the
710      * device should be used {@link #getDeviceDate}.
711      *
712      * <p>
713      *
714      * @param date in millisecond since epoch format of when to start the snapshot until present.
715      *     (can be be obtained using 'date +%s')
716      */
717     @MustBeClosed
getLogcatSince(long date)718     public InputStreamSource getLogcatSince(long date);
719 
720     /**
721      * Grabs a snapshot stream of the last <code>maxBytes</code> of captured logcat data.
722      *
723      * <p>Useful for cases when you want to capture frequent snapshots of the captured logcat data
724      * without incurring the potentially big disk space penalty of getting the entire {@link
725      * #getLogcat()} snapshot.
726      *
727      * @param maxBytes the maximum amount of data to return. Should be an amount that can
728      *     comfortably fit in memory
729      */
730     @MustBeClosed
getLogcat(int maxBytes)731     public InputStreamSource getLogcat(int maxBytes);
732 
733     /**
734      * Get a dump of the current logcat for device. Unlike {@link #getLogcat()}, this method will
735      * always return a static dump of the logcat.
736      *
737      * <p>Has the disadvantage that nothing will be returned if device is not reachable.
738      *
739      * @return a {@link InputStreamSource} of the logcat data. An empty stream is returned if fail
740      *     to capture logcat data.
741      */
742     @MustBeClosed
getLogcatDump()743     public InputStreamSource getLogcatDump();
744 
745     /**
746      * Perform instructions to configure device for testing that after every boot.
747      * <p/>
748      * Should be called after device is fully booted/available
749      * <p/>
750      * In normal circumstances this method doesn't need to be called explicitly, as
751      * implementations should perform these steps automatically when performing a reboot.
752      * <p/>
753      * Where it may need to be called is when device reboots due to other events (eg when a
754      * fastboot update command has completed)
755      *
756      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
757      * recovered.
758      */
postBootSetup()759     public void postBootSetup() throws DeviceNotAvailableException;
760 
761     /**
762      * Reboots the device into bootloader mode.
763      * <p/>
764      * Blocks until device is in bootloader mode.
765      *
766      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
767      * recovered.
768      */
rebootIntoBootloader()769     public void rebootIntoBootloader() throws DeviceNotAvailableException;
770 
771     /**
772      * Reboots the device into adb mode.
773      * <p/>
774      * Blocks until device becomes available.
775      *
776      * @throws DeviceNotAvailableException if device is not available after reboot
777      */
reboot()778     public void reboot() throws DeviceNotAvailableException;
779 
780     /**
781      * Reboots the device into adb recovery mode.
782      * <p/>
783      * Blocks until device enters recovery
784      *
785      * @throws DeviceNotAvailableException if device is not available after reboot
786      */
rebootIntoRecovery()787     public void rebootIntoRecovery() throws DeviceNotAvailableException;
788 
789     /**
790      * An alternate to {@link #reboot()} that only blocks until device is online ie visible to adb.
791      *
792      * @throws DeviceNotAvailableException if device is not available after reboot
793      */
rebootUntilOnline()794     public void rebootUntilOnline() throws DeviceNotAvailableException;
795 
796     /**
797      * Issues a command to reboot device and returns on command complete and when device is no
798      * longer visible to adb.
799      *
800      * @throws DeviceNotAvailableException
801      */
nonBlockingReboot()802     public void nonBlockingReboot() throws DeviceNotAvailableException;
803 
804     /**
805      * Turns on adb root. If the "enable-root" setting is "false", will log a message and
806      * return without enabling root.
807      * <p/>
808      * Enabling adb root may cause device to disconnect from adb. This method will block until
809      * device is available.
810      *
811      * @return <code>true</code> if successful.
812      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
813      * recovered.
814      */
enableAdbRoot()815     public boolean enableAdbRoot() throws DeviceNotAvailableException;
816 
817     /**
818      * Turns off adb root.
819      * <p/>
820      * Disabling adb root may cause device to disconnect from adb. This method will block until
821      * device is available.
822      *
823      * @return <code>true</code> if successful.
824      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
825      * recovered.
826      */
disableAdbRoot()827     public boolean disableAdbRoot() throws DeviceNotAvailableException;
828 
829     /**
830      * @return <code>true</code> if device currently has adb root, <code>false</code> otherwise.
831      *
832      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
833      * recovered.
834      */
isAdbRoot()835     public boolean isAdbRoot() throws DeviceNotAvailableException;
836 
837     /**
838      * Encrypts the device.
839      * <p/>
840      * Encrypting the device may be done inplace or with a wipe.  Inplace encryption will not wipe
841      * any data on the device but normally takes a couple orders of magnitude longer than the wipe.
842      * <p/>
843      * This method will reboot the device if it is not already encrypted and will block until device
844      * is online.  Also, it will not decrypt the device after the reboot.  Therefore, the device
845      * might not be fully booted and/or ready to be tested when this method returns.
846      *
847      * @param inplace if the encryption process should take inplace and the device should not be
848      * wiped.
849      * @return <code>true</code> if successful.
850      * @throws DeviceNotAvailableException if device is not available after reboot.
851      * @throws UnsupportedOperationException if encryption is not supported on the device.
852      */
encryptDevice(boolean inplace)853     public boolean encryptDevice(boolean inplace) throws DeviceNotAvailableException,
854             UnsupportedOperationException;
855 
856     /**
857      * Unencrypts the device.
858      * <p/>
859      * Unencrypting the device may cause device to be wiped and may reboot device. This method will
860      * block until device is available and ready for testing.  Requires fastboot inorder to wipe the
861      * userdata partition.
862      *
863      * @return <code>true</code> if successful.
864      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
865      * recovered.
866      * @throws UnsupportedOperationException if encryption is not supported on the device.
867      */
unencryptDevice()868     public boolean unencryptDevice() throws DeviceNotAvailableException,
869             UnsupportedOperationException;
870 
871     /**
872      * Unlocks the device if the device is in an encrypted state.
873      * </p>
874      * This method may restart the framework but will not call {@link #postBootSetup()}. Therefore,
875      * the device might not be fully ready to be tested when this method returns.
876      *
877      * @return <code>true</code> if successful or if the device is unencrypted.
878      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
879      * recovered.
880      * @throws UnsupportedOperationException if encryption is not supported on the device.
881      */
unlockDevice()882     public boolean unlockDevice() throws DeviceNotAvailableException,
883             UnsupportedOperationException;
884 
885     /**
886      * Returns if the device is encrypted.
887      *
888      * @return <code>true</code> if the device is encrypted.
889      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
890      * recovered.
891      */
isDeviceEncrypted()892     public boolean isDeviceEncrypted() throws DeviceNotAvailableException;
893 
894     /**
895      * Returns if encryption is supported on the device.
896      *
897      * @return <code>true</code> if the device supports encryption.
898      * @throws DeviceNotAvailableException
899      */
isEncryptionSupported()900     public boolean isEncryptionSupported() throws DeviceNotAvailableException;
901 
902     /**
903      * Waits for the device to be responsive and available for testing.
904      *
905      * @param waitTime the time in ms to wait
906      * @throws DeviceNotAvailableException if device is still unresponsive after waitTime expires.
907      */
waitForDeviceAvailable(final long waitTime)908     public void waitForDeviceAvailable(final long waitTime) throws DeviceNotAvailableException;
909 
910     /**
911      * Waits for the device to be responsive and available for testing.  Uses default timeout.
912      *
913      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
914      * recovered.
915      */
waitForDeviceAvailable()916     public void waitForDeviceAvailable() throws DeviceNotAvailableException;
917 
918     /**
919      * Blocks until device is visible via adb.
920      * <p/>
921      * Note the device may not necessarily be responsive to commands on completion. Use
922      * {@link #waitForDeviceAvailable()} instead.
923      *
924      * @param waitTime the time in ms to wait
925      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
926      * recovered.
927      */
waitForDeviceOnline(final long waitTime)928     public void waitForDeviceOnline(final long waitTime) throws DeviceNotAvailableException;
929 
930     /**
931      * Blocks until device is visible via adb.  Uses default timeout
932      * <p/>
933      * Note the device may not necessarily be responsive to commands on completion. Use
934      * {@link #waitForDeviceAvailable()} instead.
935      *
936      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
937      * recovered.
938      */
waitForDeviceOnline()939     public void waitForDeviceOnline() throws DeviceNotAvailableException;
940 
941     /**
942      * Blocks for the device to be not available ie missing from adb
943      *
944      * @param waitTime the time in ms to wait
945      * @return <code>true</code> if device becomes not available before time expires.
946      *         <code>false</code> otherwise
947      */
waitForDeviceNotAvailable(final long waitTime)948     public boolean waitForDeviceNotAvailable(final long waitTime);
949 
950     /**
951      * Blocks for the device to be in the 'adb recovery' state (note this is distinct from
952      * {@link IDeviceRecovery}).
953      *
954      * @param waitTime the time in ms to wait
955      * @return <code>true</code> if device boots into recovery before time expires.
956      *         <code>false</code> otherwise
957      */
waitForDeviceInRecovery(final long waitTime)958     public boolean waitForDeviceInRecovery(final long waitTime);
959 
960     /**
961      * Waits for device to be responsive to a basic adb shell command.
962      *
963      * @param waitTime the time in ms to wait
964      * @return <code>true</code> if device becomes responsive before <var>waitTime</var> elapses.
965      */
waitForDeviceShell(final long waitTime)966     public boolean waitForDeviceShell(final long waitTime);
967 
968     /**
969      * Blocks until the device's boot complete flag is set.
970      *
971      * @param timeOut time in msecs to wait for the flag to be set
972      * @return true if device's boot complete flag is set within the timeout
973      * @throws DeviceNotAvailableException
974      */
waitForBootComplete(long timeOut)975     public boolean waitForBootComplete(long timeOut) throws DeviceNotAvailableException;
976 
977     /**
978      * Set the {@link IDeviceRecovery} to use for this device. Should be set when device is first
979      * allocated.
980      *
981      * @param recovery the {@link IDeviceRecovery}
982      */
setRecovery(IDeviceRecovery recovery)983     public void setRecovery(IDeviceRecovery recovery);
984 
985     /**
986      * Set the current recovery mode to use for the device.
987      * <p/>
988      * Used to control what recovery method to use when a device communication problem is
989      * encountered. Its recommended to only use this method sparingly when needed (for example,
990      * when framework is down, etc
991      *
992      * @param mode whether 'recover till online only' mode should be on or not.
993      */
setRecoveryMode(RecoveryMode mode)994     public void setRecoveryMode(RecoveryMode mode);
995 
996     /**
997      * Get the current recovery mode used for the device.
998      *
999      * @return the current recovery mode used for the device.
1000      */
getRecoveryMode()1001     public RecoveryMode getRecoveryMode();
1002 
1003     /**
1004      * Get the device's state.
1005      */
getDeviceState()1006     public TestDeviceState getDeviceState();
1007 
1008     /**
1009      * @return <code>true</code> if device is connected to adb-over-tcp, <code>false</code>
1010      * otherwise.
1011      */
isAdbTcp()1012     public boolean isAdbTcp();
1013 
1014     /**
1015      * Switch device to adb-over-tcp mode.
1016      *
1017      * @return the tcp serial number or <code>null</code> if device could not be switched
1018      * @throws DeviceNotAvailableException
1019      */
switchToAdbTcp()1020     public String switchToAdbTcp() throws DeviceNotAvailableException;
1021 
1022     /**
1023      * Switch device to adb over usb mode.
1024      *
1025      * @return <code>true</code> if switch was successful, <code>false</code> otherwise.
1026      * @throws DeviceNotAvailableException
1027      */
switchToAdbUsb()1028     public boolean switchToAdbUsb() throws DeviceNotAvailableException;
1029 
1030     /**
1031      * Get the stream of emulator stdout and stderr
1032      * @return emulator output
1033      */
getEmulatorOutput()1034     public InputStreamSource getEmulatorOutput();
1035 
1036     /**
1037      * Close and delete the emulator output.
1038      */
stopEmulatorOutput()1039     public void stopEmulatorOutput();
1040 
1041     /**
1042      * Get the device API Level. Defaults to {@link #UNKNOWN_API_LEVEL}.
1043      *
1044      * @return an integer indicating the API Level of device
1045      * @throws DeviceNotAvailableException
1046      */
getApiLevel()1047     public int getApiLevel() throws DeviceNotAvailableException;
1048 
1049     /**
1050      * Helper to get the time difference between the device and a given {@link Date}. Use Epoch time
1051      * internally.
1052      *
1053      * @return the difference in milliseconds
1054      */
getDeviceTimeOffset(Date date)1055     public long getDeviceTimeOffset(Date date) throws DeviceNotAvailableException;
1056 
1057     /**
1058      * Sets the date on device
1059      * <p>
1060      * Note: setting date on device requires root
1061      * @param date specify a particular date; will use host date if <code>null</code>
1062      * @throws DeviceNotAvailableException
1063      */
setDate(Date date)1064     public void setDate(Date date) throws DeviceNotAvailableException;
1065 
1066     /**
1067      * Return the date of the device in millisecond since epoch.
1068      *
1069      * <p>
1070      *
1071      * @return the date of the device in epoch format.
1072      * @throws DeviceNotAvailableException
1073      */
getDeviceDate()1074     public long getDeviceDate() throws DeviceNotAvailableException;
1075 
1076     /**
1077      * Make the system partition on the device writable. May reboot the device.
1078      * @throws DeviceNotAvailableException
1079      */
remountSystemWritable()1080     public void remountSystemWritable() throws DeviceNotAvailableException;
1081 
1082     /**
1083      * Returns the key type used to sign the device image
1084      * <p>
1085      * Typically Android devices may be signed with test-keys (like in AOSP) or release-keys
1086      * (controlled by individual device manufacturers)
1087      * @return The signing key if found, null otherwise.
1088      * @throws DeviceNotAvailableException
1089      */
getBuildSigningKeys()1090     public String getBuildSigningKeys() throws DeviceNotAvailableException;
1091 
1092     /**
1093      * Retrieves a bugreport from the device.
1094      * <p/>
1095      * The implementation of this is guaranteed to continue to work on a device without an sdcard
1096      * (or where the sdcard is not yet mounted).
1097      *
1098      * @return An {@link InputStreamSource} which will produce the bugreport contents on demand.  In
1099      *         case of failure, the {@code InputStreamSource} will produce an empty
1100      *         {@link InputStream}.
1101      */
getBugreport()1102     public InputStreamSource getBugreport();
1103 
1104     /**
1105      * Retrieves a bugreportz from the device. Zip format bugreport contains the main bugreport
1106      * and other log files that are useful for debugging.
1107      * <p/>
1108      * Only supported for 'adb version' > 1.0.36
1109      *
1110      * @return a {@link InputStreamSource} of the zip file containing the bugreportz, return null
1111      *         in case of failure.
1112      */
getBugreportz()1113     public InputStreamSource getBugreportz();
1114 
1115     /**
1116      * Helper method to take a bugreport and log it to the reporters.
1117      *
1118      * @param dataName name under which the bugreport will be reported.
1119      * @param listener an {@link ITestLogger} to log the bugreport.
1120      * @return True if the logging was successful, false otherwise.
1121      */
logBugreport(String dataName, ITestLogger listener)1122     public boolean logBugreport(String dataName, ITestLogger listener);
1123 
1124     /**
1125      * Take a bugreport and returns it inside a {@link Bugreport} object to handle it. Return null
1126      * in case of issue.
1127      * </p>
1128      * File referenced in the Bugreport object need to be cleaned via {@link Bugreport#close()}.
1129      */
takeBugreport()1130     public Bugreport takeBugreport();
1131 
1132     /**
1133      * Get the device class.
1134      *
1135      * @return the {@link String} device class.
1136      */
getDeviceClass()1137     public String getDeviceClass();
1138 
1139     /**
1140      * Extra steps for device specific required setup that will be executed on the device prior
1141      * to the invocation flow.
1142      */
preInvocationSetup(IBuildInfo info)1143     public void preInvocationSetup(IBuildInfo info)
1144             throws TargetSetupError, DeviceNotAvailableException;
1145 
1146     /**
1147      * Extra steps for device specific required clean up that will be executed after the invocation
1148      * is done.
1149      */
postInvocationTearDown()1150     public void postInvocationTearDown();
1151 
1152     /**
1153      * Return true if the device is headless (no screen), false otherwise.
1154      */
isHeadless()1155     public boolean isHeadless() throws DeviceNotAvailableException;
1156 
1157     /**
1158      * Return a {@link DeviceDescriptor} from the device information to get info on it without
1159      * passing the actual device object.
1160      */
getDeviceDescriptor()1161     public DeviceDescriptor getDeviceDescriptor();
1162 
1163     /**
1164      * Helper method runs the "ps" command and returns list of USER, PID and NAME of all the
1165      * processes.
1166      *
1167      * @return List of ProcessInfo objects
1168      */
getProcesses()1169     public List<ProcessInfo> getProcesses() throws DeviceNotAvailableException;
1170 
1171     /**
1172      * Helper method runs the "ps" command and returns USER, PID and NAME of the given process name.
1173      *
1174      * @return ProcessInfo of given processName
1175      */
getProcessByName(String processName)1176     public ProcessInfo getProcessByName(String processName) throws DeviceNotAvailableException;
1177 
1178     /** Returns the pid of the service or null if something went wrong. */
getProcessPid(String process)1179     public String getProcessPid(String process) throws DeviceNotAvailableException;
1180 
1181     /**
1182      * Log a message in the logcat of the device. This is a safe call that will not throw even if
1183      * the logging fails.
1184      *
1185      * @param tag The tag under which we log our message in the logcat.
1186      * @param level The debug level of the message in the logcat.
1187      * @param format The message format.
1188      * @param args the args to be replaced via String.format().
1189      */
logOnDevice(String tag, LogLevel level, String format, Object... args)1190     public void logOnDevice(String tag, LogLevel level, String format, Object... args);
1191 }
1192