/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ /* 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/. */ "use strict"; const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://gre/modules/AppConstants.jsm"); const RECOVERYSERVICE_CID = Components.ID("{b3caca5d-0bb0-48c6-912b-6be6cbf08832}"); const RECOVERYSERVICE_CONTRACTID = "@mozilla.org/recovery-service;1"; function log(msg) { dump("-*- RecoveryService: " + msg + "\n"); } const isGonk = AppConstants.platform === 'gonk'; if (isGonk) { var librecovery = (function() { let library; try { library = ctypes.open("librecovery.so"); } catch (e) { log("Unable to open librecovery.so"); throw Cr.NS_ERROR_FAILURE; } // Bug 1163956, modify updatePath from ctyps.char.ptr to ctype.char.array(4096) // align with librecovery.h. 4096 comes from PATH_MAX let FotaUpdateStatus = new ctypes.StructType("FotaUpdateStatus", [ { result: ctypes.int }, { updatePath: ctypes.char.array(4096) } ]); return { factoryReset: library.declare("factoryReset", ctypes.default_abi, ctypes.int), installFotaUpdate: library.declare("installFotaUpdate", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int), FotaUpdateStatus: FotaUpdateStatus, getFotaUpdateStatus: library.declare("getFotaUpdateStatus", ctypes.default_abi, ctypes.int, FotaUpdateStatus.ptr) }; })(); } const gFactoryResetFile = "__post_reset_cmd__"; function RecoveryService() {} RecoveryService.prototype = { classID: RECOVERYSERVICE_CID, QueryInterface: XPCOMUtils.generateQI([Ci.nsIRecoveryService]), classInfo: XPCOMUtils.generateCI({ classID: RECOVERYSERVICE_CID, contractID: RECOVERYSERVICE_CONTRACTID, interfaces: [Ci.nsIRecoveryService], classDescription: "B2G Recovery Service" }), factoryReset: function RS_factoryReset(reason) { if (!isGonk) { Cr.NS_ERROR_FAILURE; } function doReset() { // If this succeeds, then the device reboots and this never returns if (librecovery.factoryReset() != 0) { log("Error: Factory reset failed. Trying again after clearing cache."); } let cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"] .getService(Ci.nsICacheStorageService); cache.clear(); if (librecovery.factoryReset() != 0) { log("Error: Factory reset failed again"); } } log("factoryReset " + reason); let commands = []; if (reason == "wipe") { let volumeService = Cc["@mozilla.org/telephony/volume-service;1"] .getService(Ci.nsIVolumeService); let volNames = volumeService.getVolumeNames(); log("Found " + volNames.length + " volumes"); for (let i = 0; i < volNames.length; i++) { let name = volNames.queryElementAt(i, Ci.nsISupportsString); let volume = volumeService.getVolumeByName(name.data); log("Got volume: " + name.data + " at " + volume.mountPoint); commands.push("wipe " + volume.mountPoint); } } else if (reason == "root") { commands.push("root"); } if (commands.length > 0) { Cu.import("resource://gre/modules/osfile.jsm"); let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); dir.initWithPath("/persist"); var postResetFile = dir.exists() ? OS.Path.join("/persist", gFactoryResetFile): OS.Path.join("/cache", gFactoryResetFile); let encoder = new TextEncoder(); let text = commands.join("\n"); let array = encoder.encode(text); let promise = OS.File.writeAtomic(postResetFile, array, { tmpPath: postResetFile + ".tmp" }); promise.then(doReset, function onError(error) { log("Error: " + error); }); } else { doReset(); } }, installFotaUpdate: function RS_installFotaUpdate(updatePath) { if (!isGonk) { throw Cr.NS_ERROR_FAILURE; } // If this succeeds, then the device reboots and this never returns if (librecovery.installFotaUpdate(updatePath, updatePath.length) != 0) { log("Error: FOTA install failed. Trying again after clearing cache."); } var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService); cache.clear(); if (librecovery.installFotaUpdate(updatePath, updatePath.length) != 0) { log("Error: FOTA install failed again"); } }, getFotaUpdateStatus: function RS_getFotaUpdateStatus() { let status = Ci.nsIRecoveryService.FOTA_UPDATE_UNKNOWN; if (isGonk) { let cStatus = librecovery.FotaUpdateStatus(); if (librecovery.getFotaUpdateStatus(cStatus.address()) == 0) { status = cStatus.result; } } return status; } }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RecoveryService]);