зеркало из https://github.com/mozilla/gecko-dev.git
222 строки
5.9 KiB
JavaScript
222 строки
5.9 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";
|
|
|
|
const Cu = Components.utils;
|
|
const Ci = Components.interfaces;
|
|
const Cc = Components.classes;
|
|
|
|
Cu.importGlobalProperties(['FileReader']);
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Screenshot", "resource://gre/modules/Screenshot.jsm");
|
|
|
|
this.EXPORTED_SYMBOLS = ["LogCapture"];
|
|
|
|
const SYSTEM_PROPERTY_KEY_MAX = 32;
|
|
const SYSTEM_PROPERTY_VALUE_MAX = 92;
|
|
|
|
function debug(msg) {
|
|
dump("LogCapture.jsm: " + msg + "\n");
|
|
}
|
|
|
|
var LogCapture = {
|
|
ensureLoaded: function() {
|
|
if (!this.ctypes) {
|
|
this.load();
|
|
}
|
|
},
|
|
|
|
load: function() {
|
|
// load in everything on first use
|
|
Cu.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.getpid = this.libc.declare("getpid",
|
|
this.ctypes.default_abi,
|
|
this.ctypes.int // PID
|
|
);
|
|
|
|
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;
|
|
},
|
|
|
|
/**
|
|
* Dumping about:memory to a file in /data/local/tmp/, returning a Promise.
|
|
* Will be resolved with the dumped file name.
|
|
*/
|
|
readAboutMemory: function() {
|
|
this.ensureLoaded();
|
|
let deferred = Promise.defer();
|
|
|
|
// Perform the dump
|
|
let dumper = Cc["@mozilla.org/memory-info-dumper;1"]
|
|
.getService(Ci.nsIMemoryInfoDumper);
|
|
|
|
let file = "/data/local/tmp/logshake-about_memory-" + this.getpid() + ".json.gz";
|
|
dumper.dumpMemoryReportsToNamedFile(file, function() {
|
|
deferred.resolve(file);
|
|
}, null, false);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
/**
|
|
* Dumping screenshot, returning a Promise. Will be resolved with the content
|
|
* as an ArrayBuffer.
|
|
*/
|
|
getScreenshot: function() {
|
|
let deferred = Promise.defer();
|
|
try {
|
|
this.ensureLoaded();
|
|
|
|
let fr = new FileReader();
|
|
fr.onload = function(evt) {
|
|
deferred.resolve(new Uint8Array(evt.target.result));
|
|
};
|
|
|
|
fr.onerror = function(evt) {
|
|
deferred.reject(evt);
|
|
};
|
|
|
|
fr.readAsArrayBuffer(Screenshot.get());
|
|
} catch(e) {
|
|
// We pass any errors through to the deferred Promise
|
|
deferred.reject(e);
|
|
}
|
|
|
|
return deferred.promise;
|
|
}
|
|
};
|
|
|
|
this.LogCapture = LogCapture;
|