diff options
24 files changed, 18 insertions, 985 deletions
diff --git a/build/autoconf/arch.m4 b/build/autoconf/arch.m4 index 20af6ad7d..bdf7f58a5 100644 --- a/build/autoconf/arch.m4 +++ b/build/autoconf/arch.m4 @@ -28,24 +28,12 @@ MOZ_ARG_WITH_STRING(arch, if test -z "$MOZ_ARCH"; then dnl Defaults case "${CPU_ARCH}-${OS_TARGET}" in - arm-Android) - MOZ_THUMB=yes - MOZ_ARCH=armv7-a - MOZ_FPU=vfp - MOZ_FLOAT_ABI=softfp - MOZ_ALIGN=no - ;; arm-Darwin) MOZ_ARCH=toolchain-default ;; esac fi -if test "$MOZ_ARCH" = "armv6" -a "$OS_TARGET" = "Android"; then - MOZ_FPU=vfp - MOZ_FLOAT_ABI=softfp -fi - MOZ_ARG_WITH_STRING(thumb, [ --with-thumb[[=yes|no|toolchain-default]]] [ Use Thumb instruction set (-mthumb)], diff --git a/build/autoconf/config.sub b/build/autoconf/config.sub index 8d39c4ba3..74c87648f 100755 --- a/build/autoconf/config.sub +++ b/build/autoconf/config.sub @@ -114,7 +114,7 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | \ @@ -122,10 +122,6 @@ case $maybe_os in os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] @@ -1389,7 +1385,7 @@ case $os in | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -mingw32* | -mingw64* | -linux-gnu* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ diff --git a/build/autoconf/frameptr.m4 b/build/autoconf/frameptr.m4 index e7e50330e..24543b214 100644 --- a/build/autoconf/frameptr.m4 +++ b/build/autoconf/frameptr.m4 @@ -7,11 +7,6 @@ dnl disabling frame pointers in this architecture based on the configure dnl options AC_DEFUN([MOZ_SET_FRAMEPTR_FLAGS], [ - case "$target" in - *android*) - unwind_tables="-funwind-tables" - ;; - esac if test "$GNU_CC"; then MOZ_ENABLE_FRAME_PTR="-fno-omit-frame-pointer $unwind_tables" MOZ_DISABLE_FRAME_PTR="-fomit-frame-pointer" diff --git a/build/mobile/b2gautomation.py b/build/mobile/b2gautomation.py deleted file mode 100644 index a21809068..000000000 --- a/build/mobile/b2gautomation.py +++ /dev/null @@ -1,451 +0,0 @@ -# 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/. - -import datetime -import mozcrash -import threading -import os -import posixpath -import Queue -import re -import shutil -import signal -import tempfile -import time -import traceback -import zipfile - -from automation import Automation -from mozlog import get_default_logger -from mozprocess import ProcessHandlerMixin - - -class StdOutProc(ProcessHandlerMixin): - """Process handler for b2g which puts all output in a Queue. - """ - - def __init__(self, cmd, queue, **kwargs): - self.queue = queue - kwargs.setdefault('processOutputLine', []).append(self.handle_output) - ProcessHandlerMixin.__init__(self, cmd, **kwargs) - - def handle_output(self, line): - self.queue.put_nowait(line) - - -class B2GRemoteAutomation(Automation): - _devicemanager = None - - def __init__(self, deviceManager, appName='', remoteLog=None, - marionette=None): - self._devicemanager = deviceManager - self._appName = appName - self._remoteProfile = None - self._remoteLog = remoteLog - self.marionette = marionette - self._is_emulator = False - self.test_script = None - self.test_script_args = None - - # Default our product to b2g - self._product = "b2g" - self.lastTestSeen = "b2gautomation.py" - # Default log finish to mochitest standard - self.logFinish = 'INFO SimpleTest FINISHED' - Automation.__init__(self) - - def setEmulator(self, is_emulator): - self._is_emulator = is_emulator - - def setDeviceManager(self, deviceManager): - self._devicemanager = deviceManager - - def setAppName(self, appName): - self._appName = appName - - def setRemoteProfile(self, remoteProfile): - self._remoteProfile = remoteProfile - - def setProduct(self, product): - self._product = product - - def setRemoteLog(self, logfile): - self._remoteLog = logfile - - def getExtensionIDFromRDF(self, rdfSource): - """ - Retrieves the extension id from an install.rdf file (or string). - """ - from xml.dom.minidom import parse, parseString, Node - - if isinstance(rdfSource, file): - document = parse(rdfSource) - else: - document = parseString(rdfSource) - - # Find the <em:id> element. There can be multiple <em:id> tags - # within <em:targetApplication> tags, so we have to check this way. - for rdfChild in document.documentElement.childNodes: - if rdfChild.nodeType == Node.ELEMENT_NODE and rdfChild.tagName == "Description": - for descChild in rdfChild.childNodes: - if descChild.nodeType == Node.ELEMENT_NODE and descChild.tagName == "em:id": - return descChild.childNodes[0].data - return None - - def installExtension(self, extensionSource, profileDir, extensionID=None): - # Bug 827504 - installing special-powers extension separately causes problems in B2G - if extensionID != "special-powers@mozilla.org": - if not os.path.isdir(profileDir): - self.log.info("INFO | automation.py | Cannot install extension, invalid profileDir at: %s", profileDir) - return - - installRDFFilename = "install.rdf" - - extensionsRootDir = os.path.join(profileDir, "extensions", "staged") - if not os.path.isdir(extensionsRootDir): - os.makedirs(extensionsRootDir) - - if os.path.isfile(extensionSource): - reader = zipfile.ZipFile(extensionSource, "r") - - for filename in reader.namelist(): - # Sanity check the zip file. - if os.path.isabs(filename): - self.log.info("INFO | automation.py | Cannot install extension, bad files in xpi") - return - - # We may need to dig the extensionID out of the zip file... - if extensionID is None and filename == installRDFFilename: - extensionID = self.getExtensionIDFromRDF(reader.read(filename)) - - # We must know the extensionID now. - if extensionID is None: - self.log.info("INFO | automation.py | Cannot install extension, missing extensionID") - return - - # Make the extension directory. - extensionDir = os.path.join(extensionsRootDir, extensionID) - os.mkdir(extensionDir) - - # Extract all files. - reader.extractall(extensionDir) - - elif os.path.isdir(extensionSource): - if extensionID is None: - filename = os.path.join(extensionSource, installRDFFilename) - if os.path.isfile(filename): - with open(filename, "r") as installRDF: - extensionID = self.getExtensionIDFromRDF(installRDF) - - if extensionID is None: - self.log.info("INFO | automation.py | Cannot install extension, missing extensionID") - return - - # Copy extension tree into its own directory. - # "destination directory must not already exist". - shutil.copytree(extensionSource, os.path.join(extensionsRootDir, extensionID)) - - else: - self.log.info("INFO | automation.py | Cannot install extension, invalid extensionSource at: %s", extensionSource) - - # Set up what we need for the remote environment - def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False): - # Because we are running remote, we don't want to mimic the local env - # so no copying of os.environ - if env is None: - env = {} - - # We always hide the results table in B2G; it's much slower if we don't. - env['MOZ_HIDE_RESULTS_TABLE'] = '1' - return env - - def waitForNet(self): - active = False - time_out = 0 - while not active and time_out < 40: - data = self._devicemanager._runCmd(['shell', '/system/bin/netcfg']).stdout.readlines() - data.pop(0) - for line in data: - if (re.search(r'UP\s+(?:[0-9]{1,3}\.){3}[0-9]{1,3}', line)): - active = True - break - time_out += 1 - time.sleep(1) - return active - - def checkForCrashes(self, directory, symbolsPath): - crashed = False - remote_dump_dir = self._remoteProfile + '/minidumps' - print "checking for crashes in '%s'" % remote_dump_dir - if self._devicemanager.dirExists(remote_dump_dir): - local_dump_dir = tempfile.mkdtemp() - self._devicemanager.getDirectory(remote_dump_dir, local_dump_dir) - try: - logger = get_default_logger() - if logger is not None: - crashed = mozcrash.log_crashes(logger, local_dump_dir, symbolsPath, test=self.lastTestSeen) - else: - crashed = mozcrash.check_for_crashes(local_dump_dir, symbolsPath, test_name=self.lastTestSeen) - except: - traceback.print_exc() - finally: - shutil.rmtree(local_dump_dir) - self._devicemanager.removeDir(remote_dump_dir) - return crashed - - def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs): - # if remote profile is specified, use that instead - if (self._remoteProfile): - profileDir = self._remoteProfile - - cmd, args = Automation.buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs) - - return app, args - - def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, - debuggerInfo, symbolsPath, outputHandler=None): - """ Wait for tests to finish (as evidenced by a signature string - in logcat), or for a given amount of time to elapse with no - output. - """ - timeout = timeout or 120 - while True: - lines = proc.getStdoutLines(timeout) - if lines: - currentlog = '\n'.join(lines) - - if outputHandler: - for line in lines: - outputHandler(line) - else: - print(currentlog) - - # Match the test filepath from the last TEST-START line found in the new - # log content. These lines are in the form: - # ... INFO TEST-START | /filepath/we/wish/to/capture.html\n - testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", currentlog) - if testStartFilenames: - self.lastTestSeen = testStartFilenames[-1] - if (outputHandler and outputHandler.suite_finished) or ( - hasattr(self, 'logFinish') and self.logFinish in currentlog): - return 0 - else: - self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed " - "out after %d seconds with no output", - self.lastTestSeen, int(timeout)) - self._devicemanager.killProcess('/system/b2g/b2g', sig=signal.SIGABRT) - - timeout = 10 # seconds - starttime = datetime.datetime.utcnow() - while datetime.datetime.utcnow() - starttime < datetime.timedelta(seconds=timeout): - if not self._devicemanager.processExist('/system/b2g/b2g'): - break - time.sleep(1) - else: - print "timed out after %d seconds waiting for b2g process to exit" % timeout - return 1 - - self.checkForCrashes(None, symbolsPath) - return 1 - - def getDeviceStatus(self, serial=None): - # Get the current status of the device. If we know the device - # serial number, we look for that, otherwise we use the (presumably - # only) device shown in 'adb devices'. - serial = serial or self._devicemanager._deviceSerial - status = 'unknown' - - for line in self._devicemanager._runCmd(['devices']).stdout.readlines(): - result = re.match('(.*?)\t(.*)', line) - if result: - thisSerial = result.group(1) - if not serial or thisSerial == serial: - serial = thisSerial - status = result.group(2) - - return (serial, status) - - def restartB2G(self): - # TODO hangs in subprocess.Popen without this delay - time.sleep(5) - self._devicemanager._checkCmd(['shell', 'stop', 'b2g']) - # Wait for a bit to make sure B2G has completely shut down. - time.sleep(10) - self._devicemanager._checkCmd(['shell', 'start', 'b2g']) - if self._is_emulator: - self.marionette.emulator.wait_for_port(self.marionette.port) - - def rebootDevice(self): - # find device's current status and serial number - serial, status = self.getDeviceStatus() - - # reboot! - self._devicemanager._runCmd(['shell', '/system/bin/reboot']) - - # The above command can return while adb still thinks the device is - # connected, so wait a little bit for it to disconnect from adb. - time.sleep(10) - - # wait for device to come back to previous status - print 'waiting for device to come back online after reboot' - start = time.time() - rserial, rstatus = self.getDeviceStatus(serial) - while rstatus != 'device': - if time.time() - start > 120: - # device hasn't come back online in 2 minutes, something's wrong - raise Exception("Device %s (status: %s) not back online after reboot" % (serial, rstatus)) - time.sleep(5) - rserial, rstatus = self.getDeviceStatus(serial) - print 'device:', serial, 'status:', rstatus - - def Process(self, cmd, stdout=None, stderr=None, env=None, cwd=None): - # On a desktop or fennec run, the Process method invokes a gecko - # process in which to the tests. For B2G, we simply - # reboot the device (which was configured with a test profile - # already), wait for B2G to start up, and then navigate to the - # test url using Marionette. There doesn't seem to be any way - # to pass env variables into the B2G process, but this doesn't - # seem to matter. - - # reboot device so it starts up with the mochitest profile - # XXX: We could potentially use 'stop b2g' + 'start b2g' to achieve - # a similar effect; will see which is more stable while attempting - # to bring up the continuous integration. - if not self._is_emulator: - self.rebootDevice() - time.sleep(5) - #wait for wlan to come up - if not self.waitForNet(): - raise Exception("network did not come up, please configure the network" + - " prior to running before running the automation framework") - - # stop b2g - self._devicemanager._runCmd(['shell', 'stop', 'b2g']) - time.sleep(5) - - # For some reason user.js in the profile doesn't get picked up. - # Manually copy it over to prefs.js. See bug 1009730 for more details. - self._devicemanager.moveTree(posixpath.join(self._remoteProfile, 'user.js'), - posixpath.join(self._remoteProfile, 'prefs.js')) - - # relaunch b2g inside b2g instance - instance = self.B2GInstance(self._devicemanager, env=env) - - time.sleep(5) - - # Set up port forwarding again for Marionette, since any that - # existed previously got wiped out by the reboot. - if not self._is_emulator: - self._devicemanager._checkCmd(['forward', - 'tcp:%s' % self.marionette.port, - 'tcp:%s' % self.marionette.port]) - - if self._is_emulator: - self.marionette.emulator.wait_for_port(self.marionette.port) - else: - time.sleep(5) - - # start a marionette session - session = self.marionette.start_session() - if 'b2g' not in session: - raise Exception("bad session value %s returned by start_session" % session) - - with self.marionette.using_context(self.marionette.CONTEXT_CHROME): - self.marionette.execute_script(""" - let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer"; - Components.utils.import("resource://gre/modules/Services.jsm"); - Services.prefs.setBoolPref(SECURITY_PREF, true); - - if (!testUtils.hasOwnProperty("specialPowersObserver")) { - let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"] - .getService(Components.interfaces.mozIJSSubScriptLoader); - loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm", - testUtils); - testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver(); - testUtils.specialPowersObserver.init(); - } - """) - - # run the script that starts the tests - if self.test_script: - if os.path.isfile(self.test_script): - script = open(self.test_script, 'r') - self.marionette.execute_script(script.read(), script_args=self.test_script_args) - script.close() - elif isinstance(self.test_script, basestring): - self.marionette.execute_script(self.test_script, script_args=self.test_script_args) - else: - # assumes the tests are started on startup automatically - pass - - return instance - - # be careful here as this inner class doesn't have access to outer class members - class B2GInstance(object): - """Represents a B2G instance running on a device, and exposes - some process-like methods/properties that are expected by the - automation. - """ - - def __init__(self, dm, env=None): - self.dm = dm - self.env = env or {} - self.stdout_proc = None - self.queue = Queue.Queue() - - # Launch b2g in a separate thread, and dump all output lines - # into a queue. The lines in this queue are - # retrieved and returned by accessing the stdout property of - # this class. - cmd = [self.dm._adbPath] - if self.dm._deviceSerial: - cmd.extend(['-s', self.dm._deviceSerial]) - cmd.append('shell') - for k, v in self.env.iteritems(): - cmd.append("%s=%s" % (k, v)) - cmd.append('/system/bin/b2g.sh') - proc = threading.Thread(target=self._save_stdout_proc, args=(cmd, self.queue)) - proc.daemon = True - proc.start() - - def _save_stdout_proc(self, cmd, queue): - self.stdout_proc = StdOutProc(cmd, queue) - self.stdout_proc.run() - if hasattr(self.stdout_proc, 'processOutput'): - self.stdout_proc.processOutput() - self.stdout_proc.wait() - self.stdout_proc = None - - @property - def pid(self): - # a dummy value to make the automation happy - return 0 - - def getStdoutLines(self, timeout): - # Return any lines in the queue used by the - # b2g process handler. - lines = [] - # get all of the lines that are currently available - while True: - try: - lines.append(self.queue.get_nowait()) - except Queue.Empty: - break - - # wait 'timeout' for any additional lines - if not lines: - try: - lines.append(self.queue.get(True, timeout)) - except Queue.Empty: - pass - return lines - - def wait(self, timeout=None): - # this should never happen - raise Exception("'wait' called on B2GInstance") - - def kill(self): - # this should never happen - raise Exception("'kill' called on B2GInstance") - diff --git a/build/mobile/remoteautomation.py b/build/mobile/remoteautomation.py deleted file mode 100644 index f098d5bba..000000000 --- a/build/mobile/remoteautomation.py +++ /dev/null @@ -1,401 +0,0 @@ -# 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/. - -import datetime -import glob -import time -import re -import os -import posixpath -import tempfile -import shutil -import subprocess -import sys - -from automation import Automation -from mozdevice import DMError, DeviceManager -from mozlog import get_default_logger -import mozcrash - -# signatures for logcat messages that we don't care about much -fennecLogcatFilters = [ "The character encoding of the HTML document was not declared", - "Use of Mutation Events is deprecated. Use MutationObserver instead.", - "Unexpected value from nativeGetEnabledTags: 0" ] - -class RemoteAutomation(Automation): - _devicemanager = None - - # Part of a hack for Robocop: "am COMMAND" is handled specially if COMMAND - # is in this set. See usages below. - _specialAmCommands = ('instrument', 'start') - - def __init__(self, deviceManager, appName = '', remoteLog = None, - processArgs=None): - self._devicemanager = deviceManager - self._appName = appName - self._remoteProfile = None - self._remoteLog = remoteLog - self._processArgs = processArgs or {}; - - # Default our product to fennec - self._product = "fennec" - self.lastTestSeen = "remoteautomation.py" - Automation.__init__(self) - - def setDeviceManager(self, deviceManager): - self._devicemanager = deviceManager - - def setAppName(self, appName): - self._appName = appName - - def setRemoteProfile(self, remoteProfile): - self._remoteProfile = remoteProfile - - def setProduct(self, product): - self._product = product - - def setRemoteLog(self, logfile): - self._remoteLog = logfile - - # Set up what we need for the remote environment - def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False, dmdPath=None, lsanPath=None): - # Because we are running remote, we don't want to mimic the local env - # so no copying of os.environ - if env is None: - env = {} - - if dmdPath: - env['MOZ_REPLACE_MALLOC_LIB'] = os.path.join(dmdPath, 'libdmd.so') - - # Except for the mochitest results table hiding option, which isn't - # passed to runtestsremote.py as an actual option, but through the - # MOZ_HIDE_RESULTS_TABLE environment variable. - if 'MOZ_HIDE_RESULTS_TABLE' in os.environ: - env['MOZ_HIDE_RESULTS_TABLE'] = os.environ['MOZ_HIDE_RESULTS_TABLE'] - - env['MOZ_CRASHREPORTER_DISABLE'] = '1' - - # Crash on non-local network connections by default. - # MOZ_DISABLE_NONLOCAL_CONNECTIONS can be set to "0" to temporarily - # enable non-local connections for the purposes of local testing. - # Don't override the user's choice here. See bug 1049688. - env.setdefault('MOZ_DISABLE_NONLOCAL_CONNECTIONS', '1') - - # Send an env var noting that we are in automation. Passing any - # value except the empty string will declare the value to exist. - # - # This may be used to disabled network connections during testing, e.g. - # Switchboard & telemetry uploads. - env.setdefault('MOZ_IN_AUTOMATION', '1') - - # Set WebRTC logging in case it is not set yet. - # On Android, environment variables cannot contain ',' so the - # standard WebRTC setting for NSPR_LOG_MODULES is not available. - # env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5,jsep:5,MediaPipelineFactory:5') - env.setdefault('R_LOG_LEVEL', '6') - env.setdefault('R_LOG_DESTINATION', 'stderr') - env.setdefault('R_LOG_VERBOSE', '1') - - return env - - def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, outputHandler=None): - """ Wait for tests to finish. - If maxTime seconds elapse or no output is detected for timeout - seconds, kill the process and fail the test. - """ - # maxTime is used to override the default timeout, we should honor that - status = proc.wait(timeout = maxTime, noOutputTimeout = timeout) - self.lastTestSeen = proc.getLastTestSeen - - topActivity = self._devicemanager.getTopActivity() - if topActivity == proc.procName: - proc.kill(True) - if status == 1: - if maxTime: - print "TEST-UNEXPECTED-FAIL | %s | application ran for longer than " \ - "allowed maximum time of %s seconds" % (self.lastTestSeen, maxTime) - else: - print "TEST-UNEXPECTED-FAIL | %s | application ran for longer than " \ - "allowed maximum time" % (self.lastTestSeen) - if status == 2: - print "TEST-UNEXPECTED-FAIL | %s | application timed out after %d seconds with no output" \ - % (self.lastTestSeen, int(timeout)) - - return status - - def deleteANRs(self): - # empty ANR traces.txt file; usually need root permissions - # we make it empty and writable so we can test the ANR reporter later - traces = "/data/anr/traces.txt" - try: - self._devicemanager.shellCheckOutput(['echo', '', '>', traces], root=True, - timeout=DeviceManager.short_timeout) - self._devicemanager.shellCheckOutput(['chmod', '666', traces], root=True, - timeout=DeviceManager.short_timeout) - except DMError: - print "Error deleting %s" % traces - pass - - def checkForANRs(self): - traces = "/data/anr/traces.txt" - if self._devicemanager.fileExists(traces): - try: - t = self._devicemanager.pullFile(traces) - if t: - stripped = t.strip() - if len(stripped) > 0: - print "Contents of %s:" % traces - print t - # Once reported, delete traces - self.deleteANRs() - except DMError: - print "Error pulling %s" % traces - except IOError: - print "Error pulling %s" % traces - else: - print "%s not found" % traces - - def deleteTombstones(self): - # delete any existing tombstone files from device - remoteDir = "/data/tombstones" - try: - self._devicemanager.shellCheckOutput(['rm', '-r', remoteDir], root=True, - timeout=DeviceManager.short_timeout) - except DMError: - # This may just indicate that the tombstone directory is missing - pass - - def checkForTombstones(self): - # pull any tombstones from device and move to MOZ_UPLOAD_DIR - remoteDir = "/data/tombstones" - blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None) - if blobberUploadDir: - if not os.path.exists(blobberUploadDir): - os.mkdir(blobberUploadDir) - if self._devicemanager.dirExists(remoteDir): - # copy tombstone files from device to local blobber upload directory - try: - self._devicemanager.shellCheckOutput(['chmod', '777', remoteDir], root=True, - timeout=DeviceManager.short_timeout) - self._devicemanager.shellCheckOutput(['chmod', '666', os.path.join(remoteDir, '*')], root=True, - timeout=DeviceManager.short_timeout) - self._devicemanager.getDirectory(remoteDir, blobberUploadDir, False) - except DMError: - # This may just indicate that no tombstone files are present - pass - self.deleteTombstones() - # add a .txt file extension to each tombstone file name, so - # that blobber will upload it - for f in glob.glob(os.path.join(blobberUploadDir, "tombstone_??")): - # add a unique integer to the file name, in case there are - # multiple tombstones generated with the same name, for - # instance, after multiple robocop tests - for i in xrange(1, sys.maxint): - newname = "%s.%d.txt" % (f, i) - if not os.path.exists(newname): - os.rename(f, newname) - break - else: - print "%s does not exist; tombstone check skipped" % remoteDir - else: - print "MOZ_UPLOAD_DIR not defined; tombstone check skipped" - - def checkForCrashes(self, directory, symbolsPath): - self.checkForANRs() - self.checkForTombstones() - - logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters) - - javaException = mozcrash.check_for_java_exception(logcat, test_name=self.lastTestSeen) - if javaException: - return True - - # No crash reporting means we can't say anything. - return False - - - def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs): - # If remote profile is specified, use that instead - if (self._remoteProfile): - profileDir = self._remoteProfile - - # Hack for robocop, if app & testURL == None and extraArgs contains the rest of the stuff, lets - # assume extraArgs is all we need - if app == "am" and extraArgs[0] in RemoteAutomation._specialAmCommands: - return app, extraArgs - - cmd, args = Automation.buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs) - # Remove -foreground if it exists, if it doesn't this just returns - try: - args.remove('-foreground') - except: - pass -#TODO: figure out which platform require NO_EM_RESTART -# return app, ['--environ:NO_EM_RESTART=1'] + args - return app, args - - def Process(self, cmd, stdout = None, stderr = None, env = None, cwd = None): - if stdout == None or stdout == -1 or stdout == subprocess.PIPE: - stdout = self._remoteLog - - return self.RProcess(self._devicemanager, cmd, stdout, stderr, env, cwd, self._appName, - **self._processArgs) - - # be careful here as this inner class doesn't have access to outer class members - class RProcess(object): - # device manager process - dm = None - def __init__(self, dm, cmd, stdout=None, stderr=None, env=None, cwd=None, app=None, - messageLogger=None): - self.dm = dm - self.stdoutlen = 0 - self.lastTestSeen = "remoteautomation.py" - self.proc = dm.launchProcess(cmd, stdout, cwd, env, True) - self.messageLogger = messageLogger - - if (self.proc is None): - if cmd[0] == 'am': - self.proc = stdout - else: - raise Exception("unable to launch process") - self.procName = cmd[0].split('/')[-1] - if cmd[0] == 'am' and cmd[1] in RemoteAutomation._specialAmCommands: - self.procName = app - - # Setting timeout at 1 hour since on a remote device this takes much longer. - # Temporarily increased to 90 minutes because no more chunks can be created. - self.timeout = 5400 - # The benefit of the following sleep is unclear; it was formerly 15 seconds - time.sleep(1) - - # Used to buffer log messages until we meet a line break - self.logBuffer = "" - - @property - def pid(self): - pid = self.dm.processExist(self.procName) - # HACK: we should probably be more sophisticated about monitoring - # running processes for the remote case, but for now we'll assume - # that this method can be called when nothing exists and it is not - # an error - if pid is None: - return 0 - return pid - - def read_stdout(self): - """ - Fetch the full remote log file using devicemanager, process them and - return whether there were any new log entries since the last call. - """ - if not self.dm.fileExists(self.proc): - return False - try: - newLogContent = self.dm.pullFile(self.proc, self.stdoutlen) - except DMError: - # we currently don't retry properly in the pullFile - # function in dmSUT, so an error here is not necessarily - # the end of the world - return False - if not newLogContent: - return False - - self.stdoutlen += len(newLogContent) - - if self.messageLogger is None: - testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", newLogContent) - if testStartFilenames: - self.lastTestSeen = testStartFilenames[-1] - print newLogContent - return True - - self.logBuffer += newLogContent - lines = self.logBuffer.split('\n') - lines = [l for l in lines if l] - - if lines: - if self.logBuffer.endswith('\n'): - # all lines are complete; no need to buffer - self.logBuffer = "" - else: - # keep the last (unfinished) line in the buffer - self.logBuffer = lines[-1] - del lines[-1] - - if not lines: - return False - - for line in lines: - # This passes the line to the logger (to be logged or buffered) - parsed_messages = self.messageLogger.write(line) - for message in parsed_messages: - if isinstance(message, dict) and message.get('action') == 'test_start': - self.lastTestSeen = message['test'] - return True - - @property - def getLastTestSeen(self): - return self.lastTestSeen - - # Wait for the remote process to end (or for its activity to go to background). - # While waiting, periodically retrieve the process output and print it. - # If the process is still running after *timeout* seconds, return 1; - # If the process is still running but no output is received in *noOutputTimeout* - # seconds, return 2; - # Else, once the process exits/goes to background, return 0. - def wait(self, timeout = None, noOutputTimeout = None): - timer = 0 - noOutputTimer = 0 - interval = 10 - if timeout == None: - timeout = self.timeout - status = 0 - top = self.procName - slowLog = False - while (top == self.procName): - # Get log updates on each interval, but if it is taking - # too long, only do it every 60 seconds - if (not slowLog) or (timer % 60 == 0): - startRead = datetime.datetime.utcnow() - hasOutput = self.read_stdout() - if (datetime.datetime.utcnow() - startRead) > datetime.timedelta(seconds=5): - slowLog = True - if hasOutput: - noOutputTimer = 0 - time.sleep(interval) - timer += interval - noOutputTimer += interval - if (timer > timeout): - status = 1 - break - if (noOutputTimeout and noOutputTimer > noOutputTimeout): - status = 2 - break - top = self.dm.getTopActivity() - # Flush anything added to stdout during the sleep - self.read_stdout() - return status - - def kill(self, stagedShutdown = False): - if stagedShutdown: - # Trigger an ANR report with "kill -3" (SIGQUIT) - self.dm.killProcess(self.procName, 3) - time.sleep(3) - # Trigger a breakpad dump with "kill -6" (SIGABRT) - self.dm.killProcess(self.procName, 6) - # Wait for process to end - retries = 0 - while retries < 3: - pid = self.dm.processExist(self.procName) - if pid and pid > 0: - print "%s still alive after SIGABRT: waiting..." % self.procName - time.sleep(5) - else: - return - retries += 1 - self.dm.killProcess(self.procName, 9) - pid = self.dm.processExist(self.procName) - if pid and pid > 0: - self.dm.killProcess(self.procName) - else: - self.dm.killProcess(self.procName) diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure index 5cdf52fb6..5a1f9a8c9 100644 --- a/build/moz.configure/init.configure +++ b/build/moz.configure/init.configure @@ -785,13 +785,3 @@ def js_option(*args, **kwargs): return value.format(opt.option) add_old_configure_arg(js_option) - - -# Bug 1278542: This function is a workaround to resolve -# |android_ndk_include|'s dependency on 'gonkdir.' The -# actual implementation is located in b2g/moz.configure. -# Remove this function as soon as 'android_ndk_include' -# depends on 'target.' -@depends('--help') -def gonkdir(_): - return None diff --git a/build/moz.configure/old.configure b/build/moz.configure/old.configure index a7b5cc7be..a9f387bc0 100644 --- a/build/moz.configure/old.configure +++ b/build/moz.configure/old.configure @@ -253,11 +253,6 @@ def old_configure_options(*options): '--libdir', '--no-create', '--prefix', - '--with-android-cxx-stl', - '--with-android-distribution-directory', - '--with-android-max-sdk', - '--with-android-min-sdk', - '--with-android-sdk', '--with-app-basename', '--with-app-name', '--with-arch', diff --git a/config/config.mk b/config/config.mk index 196a6cd66..749952271 100644 --- a/config/config.mk +++ b/config/config.mk @@ -550,14 +550,6 @@ ifeq (,$(filter $(OS_TARGET),WINNT Darwin)) CHECK_TEXTREL = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep TEXTREL > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_textrel | We do not want text relocations in libraries and programs' || true endif -ifeq ($(MOZ_WIDGET_TOOLKIT),android) -# While this is very unlikely (libc being added by the compiler at the end -# of the linker command line), if libmozglue.so ends up after libc.so, all -# hell breaks loose, so better safe than sorry, and check it's actually the -# case. -CHECK_MOZGLUE_ORDER = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep NEEDED | awk '{ libs[$$NF] = ++n } END { if (libs["[libmozglue.so]"] && libs["[libc.so]"] < libs["[libmozglue.so]"]) { print "libmozglue.so must be linked before libc.so"; exit 1 } }' -endif - define CHECK_BINARY $(call CHECK_GLIBC,$(1)) $(call CHECK_STDCXX,$(1)) diff --git a/dom/media/webspeech/synth/pico/nsPicoService.cpp b/dom/media/webspeech/synth/pico/nsPicoService.cpp index c3cf812fc..4f6c40010 100644 --- a/dom/media/webspeech/synth/pico/nsPicoService.cpp +++ b/dom/media/webspeech/synth/pico/nsPicoService.cpp @@ -514,13 +514,9 @@ nsPicoService::Init() return; } - // Use environment variable, or default android/b2g path + // Use environment variable nsAutoCString langPath(PR_GetEnv("PICO_LANG_PATH")); - if (langPath.IsEmpty()) { - langPath.AssignLiteral(GONK_PICO_LANG_PATH); - } - nsCOMPtr<nsIFile> voicesDir; NS_NewNativeLocalFile(langPath, true, getter_AddRefs(voicesDir)); diff --git a/services/sync/SyncComponents.manifest b/services/sync/SyncComponents.manifest index c58286277..afb08a855 100644 --- a/services/sync/SyncComponents.manifest +++ b/services/sync/SyncComponents.manifest @@ -2,18 +2,15 @@ # to the specific list of apps that use it so it doesn't get loaded in xpcshell. # Thus we restrict it to these apps: # -# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61} # basilisk: {ec8030f7-c20a-464f-9b0e-13a3a9e97384} # pale moon: {8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4} -# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110} -# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66} # suite (comm): {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} # graphene: {d1bfe7d9-c01e-4237-998b-7b5f960a4314} # Weave.js component {74b89fb0-f200-4ae8-a3ec-dd164117f6de} Weave.js contract @mozilla.org/weave/service;1 {74b89fb0-f200-4ae8-a3ec-dd164117f6de} -category app-startup WeaveService service,@mozilla.org/weave/service;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} application={99bceaaa-e3c6-48c1-b981-ef9b46b67d60} application={d1bfe7d9-c01e-4237-998b-7b5f960a4314} +category app-startup WeaveService service,@mozilla.org/weave/service;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4} application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} application={d1bfe7d9-c01e-4237-998b-7b5f960a4314} component {d28f8a0b-95da-48f4-b712-caf37097be41} Weave.js contract @mozilla.org/network/protocol/about;1?what=sync-log {d28f8a0b-95da-48f4-b712-caf37097be41} diff --git a/toolkit/components/aboutmemory/content/aboutMemory.js b/toolkit/components/aboutmemory/content/aboutMemory.js index 100228c4b..1411c3120 100644 --- a/toolkit/components/aboutmemory/content/aboutMemory.js +++ b/toolkit/components/aboutmemory/content/aboutMemory.js @@ -2008,18 +2008,6 @@ function saveReportsToFile() } }; - try { - fp.init(window, "Save Memory Reports", Ci.nsIFilePicker.modeSave); - } catch (ex) { - // This will fail on Android, since there is no Save as file picker there. - // Just save to the default downloads dir if it does. - Downloads.getSystemDownloadsDirectory().then(function(dirPath) { - let file = FileUtils.File(dirPath); - file.append(fp.defaultString); - fpFinish(file); - }); - - return; - } + fp.init(window, "Save Memory Reports", Ci.nsIFilePicker.modeSave); fp.open(fpCallback); } diff --git a/toolkit/components/alerts/nsIAlertsService.idl b/toolkit/components/alerts/nsIAlertsService.idl index 5629dabc9..d22d85a2e 100644 --- a/toolkit/components/alerts/nsIAlertsService.idl +++ b/toolkit/components/alerts/nsIAlertsService.idl @@ -53,9 +53,8 @@ interface nsIAlertNotification : nsISupports [optional] in boolean aRequireInteraction); /** - * The name of the notification. On Android, the name is hashed and used as - * a notification ID. Notifications will replace previous notifications with - * the same name. + * The name of the notification. Notifications will replace previous + * notifications with the same name. */ readonly attribute AString name; diff --git a/toolkit/components/blocklist/nsBlocklistService.js b/toolkit/components/blocklist/nsBlocklistService.js index e402d7660..fd4e9fee0 100644 --- a/toolkit/components/blocklist/nsBlocklistService.js +++ b/toolkit/components/blocklist/nsBlocklistService.js @@ -1039,7 +1039,7 @@ Blocklist.prototype = { // <gfxBlacklistEntry blockID="g60"> // <os>WINNT 6.0</os> - // <osversion>14</osversion> currently only used for Android + // <osversion>14</osversion> // <versionRange minVersion="42.0" maxVersion="13.0b2"/> // <vendor>0x8086</vendor> // <devices> diff --git a/toolkit/components/jsdownloads/public/mozIDownloadPlatform.idl b/toolkit/components/jsdownloads/public/mozIDownloadPlatform.idl index d4f49bb4b..ca7b8a165 100644 --- a/toolkit/components/jsdownloads/public/mozIDownloadPlatform.idl +++ b/toolkit/components/jsdownloads/public/mozIDownloadPlatform.idl @@ -16,13 +16,9 @@ interface mozIDownloadPlatform : nsISupports * Windows: * Add the download to the recent documents list * Set the file to be indexed for searching - * Mac: - * Bounce the downloads dock icon * GTK: * Add the download to the recent documents list * Save the source uri in the downloaded file's metadata - * Android: - * Scan media * * @param aSource * Source URI of the download diff --git a/toolkit/components/jsdownloads/src/DownloadCore.jsm b/toolkit/components/jsdownloads/src/DownloadCore.jsm index 0762b9d58..da1a740fb 100644 --- a/toolkit/components/jsdownloads/src/DownloadCore.jsm +++ b/toolkit/components/jsdownloads/src/DownloadCore.jsm @@ -1626,8 +1626,7 @@ this.DownloadError.prototype = { * Indicates the download was blocked because a runtime permission required to * download files was not granted. * - * This does not apply to all systems. On Android this flag is set to true if - * a needed runtime permission (storage) has not been granted by the user. + * This does not apply to all systems. */ becauseBlockedByRuntimePermissions: false, diff --git a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm index 44825c9c8..8b5c64498 100644 --- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm +++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm @@ -783,7 +783,7 @@ this.DownloadIntegration = { /** * Force a save on _store if it exists. Used to ensure downloads do not - * persist after being sanitized on Android. + * persist after being sanitized. * * @return {Promise} * @resolves When _store.save() completes. diff --git a/toolkit/components/jsdownloads/src/Downloads.jsm b/toolkit/components/jsdownloads/src/Downloads.jsm index 4720b5b19..3f15ec003 100644 --- a/toolkit/components/jsdownloads/src/Downloads.jsm +++ b/toolkit/components/jsdownloads/src/Downloads.jsm @@ -253,16 +253,10 @@ this.Downloads = { /** * Returns the system downloads directory asynchronously. - * Mac OSX: - * User downloads directory - * XP/2K: - * My Documents/Downloads - * Vista and others: + * Windows: * User downloads directory * Linux: * XDG user dir spec, with a fallback to Home/Downloads - * Android: - * standard downloads directory i.e. /sdcard * * @return {Promise} * @resolves The downloads directory string path. diff --git a/toolkit/components/reader/AboutReader.jsm b/toolkit/components/reader/AboutReader.jsm index 3958af081..663e88050 100644 --- a/toolkit/components/reader/AboutReader.jsm +++ b/toolkit/components/reader/AboutReader.jsm @@ -237,7 +237,7 @@ AboutReader.prototype = { break; case "pagehide": - // Close the Banners Font-dropdown, cleanup Android BackPressListener. + // Close the Banners Font-dropdown, cleanup BackPressListener. this._closeDropdowns(); this._windowUnloaded = true; break; @@ -793,7 +793,7 @@ AboutReader.prototype = { let item = doc.createElement("button"); - // Put the name in a div so that Android can hide it. + // Put the name in a div so that it can be hidden if desired. let div = doc.createElement("div"); div.textContent = option.name; div.classList.add("name"); diff --git a/toolkit/content/gmp-sources/openh264.json b/toolkit/content/gmp-sources/openh264.json index a5ba3a525..7c6eb0197 100644 --- a/toolkit/content/gmp-sources/openh264.json +++ b/toolkit/content/gmp-sources/openh264.json @@ -5,11 +5,6 @@ "WINNT_x86-msvc-x64": { "alias": "WINNT_x86-msvc" }, - "Android_x86-gcc3": { - "fileUrl": "http://ciscobinary.openh264.org/openh264-android-x86-0410d336bb748149a4f560eb6108090f078254b1.zip", - "hashValue": "8ce4d4318aa6ae9ac1376500d5fceecb3df38727aa920efd9f7829c139face4a069cab683d3902e7cdb89daad2a7e928ffba120812ae343f052a833812dad387", - "filesize": 1640053 - }, "WINNT_x86-msvc": { "fileUrl": "http://ciscobinary.openh264.org/openh264-win32-0410d336bb748149a4f560eb6108090f078254b1.zip", "hashValue": "991e01c3b95fa13fac52e0512e1936f1edae42ecbbbcc55447a36915eb3ca8f836546cc780343751691e0188872e5bc56fe3ad5f23f3243e90b96a637561b89e", @@ -41,11 +36,6 @@ "hashValue": "3b52343070a2f75e91b7b0d3bb33935352237c7e1d2fdc6a467d039ffbbda6a72087f9e0a369fe95e6c4c789ff3052f0c134af721d7273db9ba66d077d85b327", "filesize": 390308 }, - "Android_arm-eabi-gcc3": { - "fileUrl": "http://ciscobinary.openh264.org/openh264-android-arm-0410d336bb748149a4f560eb6108090f078254b1.zip", - "hashValue": "7a15245c781f32df310ebb88cb8a783512eab934b38ffd889d6420473d40eddbe8a89c17cc60d4e7647c156b04d20030e1ae0081e3f90a0d8f94626ec5f4d817", - "filesize": 1515895 - }, "Darwin_x86-gcc3": { "alias": "Darwin_x86-gcc3-u-i386-x86_64" }, diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index b039e9b1f..712a11b73 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -674,7 +674,7 @@ <field name="blockedPopups">null</field> - <!-- Obsolete name for blockedPopups. Used by android. --> + <!-- Obsolete name for blockedPopups. Maybe unused. --> <property name="pageReport" onget="return this.blockedPopups;" readonly="true"/> diff --git a/toolkit/moz.configure b/toolkit/moz.configure index 4edde6bde..ef143a60b 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -4,20 +4,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. -# Profiling -# ============================================================== -# Some of the options here imply an option from js/moz.configure, -# so, need to be declared before the include. -option('--enable-systrace', env='MOZ_USE_SYSTRACE', - help='Turn on systrace for the Gecko profiler on android/b2g') - -@depends('--enable-systrace', target) -def systrace(value, target): - if value: - return True - -set_define('MOZ_USE_SYSTRACE', systrace) - # JACK cubeb backend # ============================================================== option('--enable-jack', env='MOZ_JACK', diff --git a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js index 64530e67a..02c7fa29a 100644 --- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js +++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js @@ -804,7 +804,7 @@ this.XPIDatabase = { if (!addonsList.exists()) // XXX Irving believes this is broken in the case where there is no - // extensions.ini but there are bootstrap extensions (e.g. Android) + // extensions.ini but there are bootstrap extensions return null; try { diff --git a/toolkit/mozapps/installer/upload-files.mk b/toolkit/mozapps/installer/upload-files.mk index 865d2cf6a..1bbccecb2 100644 --- a/toolkit/mozapps/installer/upload-files.mk +++ b/toolkit/mozapps/installer/upload-files.mk @@ -15,11 +15,7 @@ else ifeq (,$(filter-out gtk2 gtk3 qt, $(MOZ_WIDGET_TOOLKIT))) MOZ_PKG_FORMAT = BZ2 else - ifeq (android,$(MOZ_WIDGET_TOOLKIT)) - MOZ_PKG_FORMAT = APK - else - MOZ_PKG_FORMAT = TGZ - endif + MOZ_PKG_FORMAT = TGZ endif endif endif @@ -381,14 +377,8 @@ ifndef MOZ_PACKAGER_FORMAT MOZ_PACKAGER_FORMAT = $(error MOZ_PACKAGER_FORMAT is not set) endif -ifneq (android,$(MOZ_WIDGET_TOOLKIT)) - OPTIMIZEJARS = 1 - ifneq (gonk,$(MOZ_WIDGET_TOOLKIT)) - ifdef NIGHTLY_BUILD - JAR_COMPRESSION ?= none - endif - endif -endif +# We optimize jars on all supported OS-es +OPTIMIZEJARS = 1 # A js binary is needed to perform verification of JavaScript minification. # We can only use the built binary when not cross-compiling. Environments diff --git a/xpcom/base/SystemMemoryReporter.cpp b/xpcom/base/SystemMemoryReporter.cpp index e0c49ee3d..7b851882d 100644 --- a/xpcom/base/SystemMemoryReporter.cpp +++ b/xpcom/base/SystemMemoryReporter.cpp @@ -95,12 +95,6 @@ GetBasename(const nsCString& aPath, nsACString& aOut) out.Assign(Substring(aPath, idx + 1)); } - // On Android, some entries in /dev/ashmem end with "(deleted)" (e.g. - // "/dev/ashmem/libxul.so(deleted)"). We don't care about this modifier, so - // cut it off when getting the entry's basename. - if (EndsWithLiteral(out, "(deleted)")) { - out.Assign(Substring(out, 0, out.RFind("(deleted)"))); - } out.StripChars(" "); aOut.Assign(out); |