gecko/b2g/components/LogCapture.jsm
Alexandre Lissy 3595bf3564 Bug 1079322 - Extract properties using libc functions. r=gwagner
The LogShake features allows one to shake its device to be able to dump
a set of useful logging informations. This includes several log files,
and also the Android properties. In the past, we relied on the
/dev/__properties__ file to extract their content by parsing its value.
This is duplicate work from the bionic libc and libcutils library.
Worst, the format used to store the values in this file has been changed
between JellyBean and Kitkat, so our parser was not able to dump the
values: that explains bug 1079322. To fix this we make use of some of
the underlying libc-defined functions used to iterate and get properties
values:
 - __system_property_find_nth() to retrieve one arbitrary property by
   its number (starting from 0), and this returns a struct containing
   all the informations
 - __system_property_read() to read the values contained in the struct
   that was previously retrieved
2014-11-12 06:31:00 +01:00

160 lines
4.2 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* jshint moz: true */
/* global Uint8Array, Components, dump */
'use strict';
this.EXPORTED_SYMBOLS = ['LogCapture'];
const SYSTEM_PROPERTY_KEY_MAX = 32;
const SYSTEM_PROPERTY_VALUE_MAX = 92;
function debug(msg) {
dump('LogCapture.jsm: ' + msg + '\n');
}
let LogCapture = {
ensureLoaded: function() {
if (!this.ctypes) {
this.load();
}
},
load: function() {
// load in everything on first use
Components.utils.import('resource://gre/modules/ctypes.jsm', this);
this.libc = this.ctypes.open(this.ctypes.libraryName('c'));
this.read = this.libc.declare('read',
this.ctypes.default_abi,
this.ctypes.int, // bytes read (out)
this.ctypes.int, // file descriptor (in)
this.ctypes.voidptr_t, // buffer to read into (in)
this.ctypes.size_t // size_t size of buffer (in)
);
this.open = this.libc.declare('open',
this.ctypes.default_abi,
this.ctypes.int, // file descriptor (returned)
this.ctypes.char.ptr, // path
this.ctypes.int // flags
);
this.close = this.libc.declare('close',
this.ctypes.default_abi,
this.ctypes.int, // error code (returned)
this.ctypes.int // file descriptor
);
this.property_find_nth =
this.libc.declare("__system_property_find_nth",
this.ctypes.default_abi,
this.ctypes.voidptr_t, // return value: nullable prop_info*
this.ctypes.unsigned_int); // n: the index of the property to return
this.property_read =
this.libc.declare("__system_property_read",
this.ctypes.default_abi,
this.ctypes.void_t, // return: none
this.ctypes.voidptr_t, // non-null prop_info*
this.ctypes.char.ptr, // key
this.ctypes.char.ptr); // value
this.key_buf = this.ctypes.char.array(SYSTEM_PROPERTY_KEY_MAX)();
this.value_buf = this.ctypes.char.array(SYSTEM_PROPERTY_VALUE_MAX)();
},
cleanup: function() {
this.libc.close();
this.read = null;
this.open = null;
this.close = null;
this.property_find_nth = null;
this.property_read = null;
this.key_buf = null;
this.value_buf = null;
this.libc = null;
this.ctypes = null;
},
/**
* readLogFile
* Read in /dev/log/{{log}} in nonblocking mode, which will return -1 if
* reading would block the thread.
*
* @param log {String} The log from which to read. Must be present in /dev/log
* @return {Uint8Array} Raw log data
*/
readLogFile: function(logLocation) {
this.ensureLoaded();
const O_READONLY = 0;
const O_NONBLOCK = 1 << 11;
const BUF_SIZE = 2048;
let BufType = this.ctypes.ArrayType(this.ctypes.char);
let buf = new BufType(BUF_SIZE);
let logArray = [];
let logFd = this.open(logLocation, O_READONLY | O_NONBLOCK);
if (logFd === -1) {
return null;
}
let readStart = Date.now();
let readCount = 0;
while (true) {
let count = this.read(logFd, buf, BUF_SIZE);
readCount += 1;
if (count <= 0) {
// log has return due to being nonblocking or running out of things
break;
}
for(let i = 0; i < count; i++) {
logArray.push(buf[i]);
}
}
let logTypedArray = new Uint8Array(logArray);
this.close(logFd);
return logTypedArray;
},
/**
* Get all system properties as a dict with keys mapping to values
*/
readProperties: function() {
this.ensureLoaded();
let n = 0;
let propertyDict = {};
while(true) {
let prop_info = this.property_find_nth(n);
if(prop_info.isNull()) {
break;
}
// read the prop_info into the key and value buffers
this.property_read(prop_info, this.key_buf, this.value_buf);
let key = this.key_buf.readString();;
let value = this.value_buf.readString()
propertyDict[key] = value;
n++;
}
return propertyDict;
}
};
this.LogCapture = LogCapture;