diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/ffdb.py | 133 |
1 files changed, 91 insertions, 42 deletions
diff --git a/tools/ffdb.py b/tools/ffdb.py index 6367c0e3..9734014e 100755 --- a/tools/ffdb.py +++ b/tools/ffdb.py @@ -297,6 +297,23 @@ def b2g_app_command(app_command, app_name): print 'Error! Application "' + app_name + '" was not found! Use the \'list\' command to find installed applications.' return 1 +def b2g_memory(app_name): + apps = b2g_get_appslist() + appActor = '' + for app in apps: + if str(app['localId']) == app_name or app['name'] == app_name or app['manifestURL'] == app_name or app['id'] == app_name: + appActor = send_b2g_cmd(webappsActorName, 'getAppActor', { 'manifestURL': app['manifestURL'] }) + break + if 'actor' in appActor: + memoryActor = appActor['actor']['memoryActor'] + measure = send_b2g_cmd(memoryActor, 'measure') + for k,v in measure.items(): + if k != 'from': + if k in ['otherSize', 'jsStringsSize', 'jsObjectsSize', 'styleSize', 'jsOtherSize', 'domSize', 'total']: # These are formatted in bytes + print k + ': ' + sizeof_fmt(v) + else: + print k + ': ' + str(v) + def b2g_log(app_name, clear=False): apps = b2g_get_appslist() appActor = '' @@ -349,8 +366,67 @@ def b2g_log(app_name, clear=False): else: print 'Application "' + sys.argv[2] + '" is not running!' +def b2g_screenshot(filename): + global deviceActorName + data_reply = send_b2g_cmd(deviceActorName, 'screenshotToDataURL') + data = data_reply['value'] + if not isinstance(data, basestring): # The device is sending the screenshot in multiple fragments since it's too long to fit in one message? + data_get_actor = data['actor'] + data_len = int(data['length']) + data = data['initial'] + chunk_size = 65000 + pos = len(data) + # Pull and assemble individual screenshot fragments. + while pos < data_len: + bytes_to_read = min(data_len - pos, chunk_size) + data_reply = send_b2g_cmd(data_get_actor, 'substring', { 'start': str(pos), 'end': str(pos + bytes_to_read) }) + if len(data_reply['substring']) != bytes_to_read: + print >> sys.stderr, 'Error! Expected to receive ' + str(bytes_to_read) + ' bytes of image data, but got ' + str(len(data_reply['substring'])) + ' bytes instead!' + sys.exit(1) + data += data_reply['substring'] + pos += bytes_to_read + send_b2g_cmd(data_get_actor, 'release') # We need to explicitly free the screenshot image string from the device, or the Devtools connection leaks resources! + + # Expected format is "data:image/png;base64,<base64data>" + delim = re.search(",", data).start() + data_format = data[:delim] + if data_format != "data:image/png;base64": + print >> sys.stderr, "Error: Received screenshot from device in an unexpected format '" + data_format + "'!" + sys.exit(1) + data = data[delim+1:] + + binary_data = base64.b64decode(data) + open(filename, 'wb').write(binary_data) + + def get_png_image_size(filename): + fhandle = open(filename, 'rb') + head = fhandle.read(24) + if len(head) != 24: + return (-1, -1) + check = struct.unpack('>i', head[4:8])[0] + if check != 0x0d0a1a0a: + return (-1, -1) + return struct.unpack('>ii', head[16:24]) + + width, height = get_png_image_size(filename) + if width <= 0 or height <= 0: + print >> sys.stderr, "Wrote " + sizeof_fmt(len(binary_data)) + " to file '" + filename + "', but the contents may be corrupted!" + else: + print "Wrote " + sizeof_fmt(len(binary_data)) + " to file '" + filename + "' (" + str(width) + 'x' + str(height) + ' pixels).' + +def b2g_get_description(desc): + global deviceActorName + data_reply = send_b2g_cmd(deviceActorName, 'getDescription') + # First try an exact match to requested desc + if desc and desc in data_reply['value']: + print desc + ': ' + str(data_reply['value'][desc]) + else: # Print all with case-insensitive substring search + for k,v in data_reply['value'].items(): + if not desc or desc.lower() in k.lower(): + print k + ': ' + str(v) + def main(): - global b2g_socket, webappsActorName, HOST, PORT, VERBOSE, ADB + global b2g_socket, webappsActorName, deviceActorName, HOST, PORT, VERBOSE, ADB if len(sys.argv) < 2 or '--help' in sys.argv or 'help' in sys.argv or '-v' in sys.argv: print '''Firefox OS Debug Bridge, a tool for automating FFOS device tasks from the command line. @@ -369,11 +445,15 @@ def main(): If the --log option is passed, ffdb will start persistently logging the execution of the installed application. log <app> [--clear]: Starts a persistent log listener that reads web console messages from the given application. If --clear is passed, the message log for that application is cleared instead. + memory <app>: Dumps a memory usage summary for the given application. navigate <url>: Opens the given web page in the B2G browser. screenshot [filename.png]: Takes a screenshot of the current contents displayed on the device. If an optional filename is specified, the screenshot is saved to that file. Otherwise the filename will be autogenerated. - get <pref>: Fetches the value of the given developer pref option from the FFOS device and prints it to console. + get [pref]: Fetches the value of the given developer pref option from the FFOS device and prints it to console. The parameter pref + is optional and may either be the full name of a pref, or a substring to search for. All matching prefs will be printed. + If no pref parameter is given, all prefs are printed. + NOTE: This function (currently at least) only reports prefs that have been explicitly set and don't have their default value. set <pref> <value>: Writes the given pref option to the FFOS device and restarts the B2G process on it for the change to take effect. unset <pref>: Removes the given pref option from the FFOS device and restarts the B2G process on it for the change to take effect. @@ -381,6 +461,10 @@ def main(): provided for conveniency, and is the same as calling './ffdb.py set devtools.debugger.prompt-connection false' restore-prompt: Restores the remote debugging connection dialog prompt to its default state. + desc [desc]: Fetches the value of the given device description field. These fields are read-only and describe the current system. + If the optional desc parameter is omitted, all device descriptions are printed. Otherwise the given description is + printed if it is an exact match, or all descriptions containing desc as the substring are printed. + Options: Additionally, the following options may be passed to control FFDB execution: --host <hostname>: Specifies the target network address to connect to. Default: 'localhost'. @@ -532,6 +616,8 @@ def main(): elif sys.argv[1] == 'log': clear = '-c' in sys.argv or '-clear' in sys.argv or '--clear' in sys.argv b2g_log(sys.argv[2], clear) + elif sys.argv[1] == 'memory': + b2g_memory(sys.argv[2]) elif sys.argv[1] == 'screenshot': if len(sys.argv) >= 3: filename = sys.argv[2] @@ -541,46 +627,7 @@ def main(): else: filename = time.strftime("screen_%Y%m%d_%H%M%S.png", time.gmtime()) - data_reply = send_b2g_cmd(deviceActorName, 'screenshotToDataURL') - data = data_reply['value'] - data_get_actor = data['actor'] - data_len = int(data['length']) - data_str = data['initial'] - delim = re.search(",", data_str).start() - data_format = data_str[:delim] - if data_format != "data:image/png;base64": - print >> sys.stderr, "Error: Received screenshot from device in an unexpected format '" + data_format + "'!" - sys.exit(1) - data = data_str[delim+1:] - chunk_size = 65000 - pos = len(data_str) - while pos < data_len: - bytes_to_read = min(data_len - pos, chunk_size) - data_reply = send_b2g_cmd(data_get_actor, 'substring', { 'start': str(pos), 'end': str(pos + bytes_to_read) }) - if len(data_reply['substring']) != bytes_to_read: - print >> sys.stderr, 'Error! Expected to receive ' + str(bytes_to_read) + ' bytes of image data, but got ' + str(len(data_reply['substring'])) + ' bytes instead!' - sys.exit(1) - data += data_reply['substring'] - pos += bytes_to_read - send_b2g_cmd(data_get_actor, 'release') # We need to explicitly free the screenshot image string from the device, or the Devtools connection leaks resources! - binary_data = base64.b64decode(data) - open(filename, 'wb').write(binary_data) - - def get_png_image_size(filename): - fhandle = open(filename, 'rb') - head = fhandle.read(24) - if len(head) != 24: - return (-1, -1) - check = struct.unpack('>i', head[4:8])[0] - if check != 0x0d0a1a0a: - return (-1, -1) - return struct.unpack('>ii', head[16:24]) - - width, height = get_png_image_size(filename) - if width <= 0 or height <= 0: - print >> sys.stderr, "Wrote " + sizeof_fmt(len(binary_data)) + " to file '" + filename + "', but the contents may be corrupted!" - else: - print "Wrote " + sizeof_fmt(len(binary_data)) + " to file '" + filename + "' (" + str(width) + 'x' + str(height) + ' pixels).' + b2g_screenshot(filename) elif sys.argv[1] == 'get': b2g_get_pref(sys.argv[2] if len(sys.argv) >= 3 else None) elif sys.argv[1] == 'set': @@ -603,6 +650,8 @@ def main(): b2g_set_pref('devtools.debugger.prompt-connection', 'false') elif sys.argv[1] == 'restore-prompt': b2g_set_pref('devtools.debugger.prompt-connection', None) + elif sys.argv[1] == 'desc': + b2g_get_description(sys.argv[2] if len(sys.argv) >= 3 else None) else: print "Unknown command '" + sys.argv[1] + "'! Pass --help for instructions." |