def execute_adb_command2(adb_cmd, piped_into_cmd=None, ignore_stderr=False, device_serial=None): adb_prefix = _adb_prefix if device_serial: adb_prefix = '%s -s %s' % (adb_prefix, device_serial) final_cmd = ('%s %s' % (adb_prefix, adb_cmd)) if piped_into_cmd: final_cmd = '%s | %s' % (final_cmd, piped_into_cmd) print_verbose("Executing \"%s\"" % final_cmd) ps1 = subprocess.Popen(final_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout_data, stderr_data = ps1.communicate() return_code = ps1.returncode try: stdout_data = stdout_data.decode('utf-8') except UnicodeDecodeError: print_error( 'Unable to decode data as UTF-8, defaulting to printing the binary data' ) stderr_data = stderr_data.decode('utf-8') _check_for_adb_not_found_error(stderr_data) _check_for_more_than_one_device_error(stderr_data) _check_for_device_not_found_error(stderr_data) if not ignore_stderr and stderr_data: print_error(stderr_data) if not stdout_data: return return_code, None, stderr_data # stdout_data is not None if isinstance(stdout_data, bytes): print_verbose("Result is \"%s\"" % stdout_data) return return_code, stdout_data, stderr_data # str for Python 3, this used to be unicode type for python 2 elif isinstance(stdout_data, str): output = '' first_line = True for line in stdout_data.split('\n'): line = line.strip() if not line: continue if line in _IGNORED_LINES: continue if first_line: output += line first_line = False else: output += '\n' + line print_verbose("Result is \"%s\"" % output) return return_code, output, stderr_data else: print_error_and_exit('stdout_data is weird type: %s' % type(stdout_data))
def get_device_android_api_version(device_serial=None): version_string = get_adb_shell_property('ro.build.version.sdk', device_serial=device_serial) if version_string is None: print_error_and_exit( 'Unable to get Android device version, is it still connected?') return int(version_string)
def _fail_with_python2_warning(): msg = ( 'You are using Python 2\nADB-enhanced no longer supports Python 2.\n' + 'Install Python 3 and then re-install this tool using\n' + '\"sudo pip uninstall adb-enhanced && sudo pip3 install adb-enhanced\"' ) print_error_and_exit(msg)
def _check_for_adb_not_found_error(stderr_data): if not stderr_data: return stderr_data = stderr_data.strip() if stderr_data.endswith('%s: command not found' % _adb_prefix): message = 'ADB (Android debug bridge) command not found.\n' message += 'Install ADB via https://developer.android.com/studio/releases/platform-tools.html' print_error_and_exit(message)
def _check_for_device_not_found_error(stderr_data): if not stderr_data: return for line in stderr_data.split('\n'): line = line.strip() if line and len(line) > 0: print_verbose(line) if line.find('error: device') > -1 and line.find('not found') > -1: print_error_and_exit(line)
def validate_options(args): count = 0 if args['--emulator']: count += 1 if args['--device']: count += 1 if args['--serial']: count += 1 if count > 1: print_error_and_exit('Only one out of -e, -d, or -s can be provided')
def _check_for_more_than_one_device_error(stderr_data): if not stderr_data: return for line in stderr_data.split('\n'): line = line.strip() if line and len(line) > 0: print_verbose(line) if line.find('error: more than one') != -1: message = '' message += 'More than one device/emulator are connected.\n' message += 'Please select a device by providing the serial ID (-s parameter).\n' message += 'You can list all connected devices/emulators via \"devices\" subcommand.' print_error_and_exit(message)
def main(): if _using_python2(): _fail_with_python2_warning() args = docopt.docopt(USAGE_STRING, version=get_version()) set_verbose(args['--verbose']) validate_options(args) options = get_generic_options_from_args(args) if options: adb_prefix = '%s %s' % (adb_helper.get_adb_prefix(), options) adb_helper.set_adb_prefix(adb_prefix) # rotate if args['rotate'] and args['portrait']: adb_enhanced.handle_rotate('portrait') elif args['rotate'] and args['landscape']: adb_enhanced.handle_rotate('landscape') elif args['rotate'] and args['left']: adb_enhanced.handle_rotate('left') elif args['rotate'] and args['right']: adb_enhanced.handle_rotate('right') # gfx elif args['gfx'] and args['on']: adb_enhanced.handle_gfx('on') elif args['gfx'] and args['off']: adb_enhanced.handle_gfx('off') elif args['gfx'] and args['lines']: adb_enhanced.handle_gfx('lines') # overdraw elif args['overdraw'] and args['on']: adb_enhanced.handle_overdraw('on') elif args['overdraw'] and args['off']: adb_enhanced.handle_overdraw('off') elif args['overdraw'] and args['deut']: adb_enhanced.handle_overdraw('deut') elif args['layout']: adb_enhanced.handle_layout(args['on']) elif args['airplane']: # This command does not always work adb_enhanced.handle_airplane(args['on']) # battery elif args['battery'] and args['saver']: adb_enhanced.handle_battery_saver(args['on']) elif args['battery'] and args['level']: adb_enhanced.handle_battery_level(int(args['<percentage>'])) elif args['battery'] and args['reset']: adb_enhanced.handle_battery_reset() elif args['doze']: adb_enhanced.handle_doze(args['on']) elif args['jank']: adb_enhanced.handle_get_jank(args['<app_name>']) elif args['devices']: adb_enhanced.handle_list_devices() elif args['top-activity']: adb_enhanced.print_top_activity() elif args['dump-ui']: adb_enhanced.dump_ui(args['<xml_file>']) elif args['force-stop']: app_name = args['<app_name>'] adb_enhanced.force_stop(app_name) elif args['clear-data']: app_name = args['<app_name>'] adb_enhanced.clear_disk_data(app_name) # mobile-data elif args['mobile-data'] and args['saver']: adb_enhanced.handle_mobile_data_saver(args['on']) elif args['mobile-data']: adb_enhanced.handle_mobile_data(args['on']) elif args['wifi']: adb_enhanced.set_wifi(args['on']) elif args['rtl']: # This is not working as expected adb_enhanced.force_rtl(args['on']) elif args['screenshot']: adb_enhanced.dump_screenshot(args['<filename.png>']) elif args['screenrecord']: adb_enhanced.dump_screenrecord(args['<filename.mp4>']) elif args['dont-keep-activities']: adb_enhanced.handle_dont_keep_activities_in_background(args['on']) elif args['animations']: adb_enhanced.toggle_animations(args['on']) elif args['show-taps']: adb_enhanced.toggle_show_taps(args['on']) elif args['stay-awake-while-charging']: # Keep screen on while the device is charging. adb_enhanced.stay_awake_while_charging(args['on']) elif args['input-text']: adb_enhanced.input_text(args['<text>']) elif args['back']: adb_enhanced.press_back() elif args['open-url']: url = args['<url>'] adb_enhanced.open_url(url) elif args['permission-groups'] and args['list'] and args['all']: adb_enhanced.list_permission_groups() elif args['permissions'] and args['list']: adb_enhanced.list_permissions(args['dangerous']) elif args['permissions']: app_name = args['<app_name>'] permission_group = adb_enhanced.get_permission_group(args) permissions = adb_enhanced.get_permissions_in_permission_group(permission_group) if not permissions and \ adb_enhanced.is_permission_group_unavailable_after_api_29(permission_group) and \ adb_enhanced.get_device_android_api_version() >= 29: print_error_and_exit('Android has made contacts group empty on API 29 and beyond, ' 'your device version is %d' % adb_enhanced.get_device_android_api_version()) elif not permissions: print_error_and_exit('No permissions found in permissions group: %s' % permission_group) adb_enhanced.grant_or_revoke_runtime_permissions( app_name, args['grant'], permissions) elif args['notifications'] and args['list']: adb_enhanced.print_notifications() # apps list elif args['apps'] and args['list'] and args['all']: adb_enhanced.print_list_all_apps() elif args['apps'] and args['list'] and args['system']: adb_enhanced.list_system_apps() elif args['apps'] and args['list'] and args['third-party']: adb_enhanced.print_list_non_system_apps() elif args['apps'] and args['list'] and args['debug']: adb_enhanced.list_debug_apps() elif args['apps'] and args['list'] and args['backup-enabled']: adb_enhanced.list_allow_backup_apps() # standby bucket elif args['standby-bucket'] and args['get']: adb_enhanced.get_standby_bucket(args['<app_name>']) elif args['standby-bucket'] and args['set']: adb_enhanced.set_standby_bucket(args['<app_name>'], adb_enhanced.calculate_standby_mode(args)) elif args['restrict-background']: adb_enhanced.apply_or_remove_background_restriction(args['<app_name>'], args['true']) elif args['ls']: file_path = args['<file_path>'] long_format = args['-l'] # Always include hidden files, -a is left for backward-compatibility but is a no-op now. include_hidden_files = True recursive = args['-R'] or args['-r'] adb_enhanced.list_directory(file_path, long_format, recursive, include_hidden_files) elif args['rm']: file_path = args['<file_path>'] force_delete = args['-f'] recursive = args['-R'] or args['-r'] adb_enhanced.delete_file(file_path, force_delete, recursive) elif args['mv']: src_path = args['<src_path>'] dest_path = args['<dest_path>'] force_move = args['-f'] adb_enhanced.move_file(src_path, dest_path, force_move) elif args['pull']: remote_file_path = args['<file_path_on_android>'] local_file_path = args['<file_path_on_machine>'] copy_ancillary = args['-a'] adb_enhanced.pull_file(remote_file_path, local_file_path, copy_ancillary) elif args['push']: remote_file_path = args['<file_path_on_android>'] local_file_path = args['<file_path_on_machine>'] adb_enhanced.push_file(local_file_path, remote_file_path) elif args['cat']: file_path = args['<file_path>'] adb_enhanced.cat_file(file_path) elif args['start']: adb_enhanced.launch_app(args['<app_name>']) elif args['stop']: adb_enhanced.stop_app(args['<app_name>']) elif args['restart']: app_name = args['<app_name>'] adb_enhanced.force_stop(app_name) adb_enhanced.launch_app(app_name) # app elif args['app'] and args['info']: adb_enhanced.print_app_info(args['<app_name>']) elif args['app'] and args['path']: adb_enhanced.print_app_path(args['<app_name>']) elif args['app'] and args['signature']: adb_enhanced.print_app_signature(args['<app_name>']) elif args['app'] and args['backup']: app_name = args['<app_name>'] backup_tar_file_path = args['<backup_tar_file_path>'] if not backup_tar_file_path: backup_tar_file_path = '%s_backup.tar' % app_name adb_enhanced.perform_app_backup(app_name, backup_tar_file_path) # dark mode elif args['dark'] and args['mode']: if args['on']: adb_enhanced.set_dark_mode(True) elif args['off']: adb_enhanced.set_dark_mode(False) elif args['screen'] and args['on']: adb_enhanced.switch_screen(adb_enhanced.SCREEN_ON) elif args['screen'] and args['off']: adb_enhanced.switch_screen(adb_enhanced.SCREEN_OFF) elif args['screen'] and args['toggle']: adb_enhanced.switch_screen(adb_enhanced.SCREEN_TOGGLE) elif args['install']: file_path = args['<file_path>'] adb_enhanced.perform_install(file_path) elif args['uninstall']: adb_enhanced.perform_uninstall(args['<app_name>'], args['--first-user']) elif args['enable']: if args['wireless'] and args['debugging']: adb_enhanced.enable_wireless_debug() elif args['disable']: if args['wireless'] and args['debugging']: adb_enhanced.disable_wireless_debug() # alarm elif args['alarm'] and args['all']: adb_enhanced.alarm_manager(adb_enhanced.AlarmEnum.ALL) elif args['alarm'] and args['history']: adb_enhanced.alarm_manager(adb_enhanced.AlarmEnum.HISTORY) elif args['alarm'] and args['pending']: adb_enhanced.alarm_manager(adb_enhanced.AlarmEnum.PENDING) elif args['alarm'] and args['top']: adb_enhanced.alarm_manager(adb_enhanced.AlarmEnum.TOP) else: print_error_and_exit('Not implemented: "%s"' % ' '.join(sys.argv))
def execute_adb_command2(adb_cmd, piped_into_cmd=None, ignore_stderr=False, device_serial=None) -> [int, str, str]: """ :param adb_cmd: command to run inside the adb shell (so, don't prefix it with "adb") :param piped_into_cmd: command to pipe the output of this command into :param ignore_stderr: if true, errors in stderr stream will be ignored while piping commands :param device_serial: device serial to send this command to (in case of multiple devices) :return: (return_code, stdout, stderr) """ adb_prefix = _adb_prefix if device_serial: adb_prefix = '%s -s %s' % (adb_prefix, device_serial) final_cmd = ('%s %s' % (adb_prefix, adb_cmd)) if piped_into_cmd: final_cmd = '%s | %s' % (final_cmd, piped_into_cmd) print_verbose("Executing \"%s\"" % final_cmd) with subprocess.Popen(final_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as ps1: stdout_data, stderr_data = ps1.communicate() return_code = ps1.returncode try: stdout_data = stdout_data.decode('utf-8') except UnicodeDecodeError: print_error( 'Unable to decode data as UTF-8, defaulting to printing the binary data' ) stderr_data = stderr_data.decode('utf-8') _check_for_adb_not_found_error(stderr_data) _check_for_more_than_one_device_error(stderr_data) _check_for_device_not_found_error(stderr_data) if not ignore_stderr and stderr_data: print_error(stderr_data) if not stdout_data: return return_code, None, stderr_data # stdout_data is not None if isinstance(stdout_data, bytes): print_verbose("Result is \"%s\"" % stdout_data) return return_code, stdout_data, stderr_data # str for Python 3, this used to be unicode type for python 2 elif isinstance(stdout_data, str): output = '' first_line = True for line in stdout_data.split('\n'): line = line.strip() if not line: continue if line in _IGNORED_LINES: continue if first_line: output += line first_line = False else: output += '\n' + line print_verbose("Result is \"%s\"" % output) return return_code, output, stderr_data else: print_error_and_exit('stdout_data is weird type: %s' % type(stdout_data))