#!/usr/bin/env python3
# Copyright 2018 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Prints the total PSS attributed to another app in Chrome's mappings.
This script assumes a device with Monochrome, and requires root access.
For instance, to get the part of Chrome's memory footprint coming from GMSCore
code and bytecode pages:
$ tools/android/native_lib_memory/java_code_pages_pss.py
--chrome-package com.android.chrome
--app-package com.google.android.gms --verbose
"""
import argparse
import logging
import os
import re
import sys
import parse_smaps
_SRC_PATH = os.path.join(
os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)
sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil'))
from devil.android import device_utils
def _GetPssInKb(mappings, app_package, verbose):
"""Returns the total PSS from mappings.
Args:
mappings: ([parse_smaps.Mapping]) List of mappings.
app_package: (str) App package to look for.
verbose: (bool) Verbose output or not.
Returns:
(executable_pss (int), other_pss (int)) Executable mappings and others,
in kB.
"""
executable_pss, other_pss = (0, 0)
for mapping in mappings:
if app_package in mapping.pathname:
if mapping.permissions == 'r-xp':
executable_pss += mapping.fields['Pss']
else:
other_pss += mapping.fields['Pss']
if verbose:
print(mapping.ToString())
return (executable_pss, other_pss)
def _CreateArgumentParser():
parser = argparse.ArgumentParser()
parser.add_argument('--chrome-package', help='Chrome package to look for.',
required=True)
parser.add_argument('--app-package', help='Application to inspect.',
required=True)
parser.add_argument('--verbose', help='Verbose output.',
action='store_true')
return parser
def main():
parser = _CreateArgumentParser()
args = parser.parse_args()
devices = device_utils.DeviceUtils.HealthyDevices()
if not devices:
logging.error('No connected devices')
return
device = devices[0]
device.EnableRoot()
processes = device.ListProcesses(args.chrome_package)
logging.basicConfig(level=logging.INFO)
logging.info('Processes:\n\t' + '\n\t'.join(p.name for p in processes))
total_executable_pss_kb, total_other_pss_kb = (0, 0)
for process in processes:
mappings = parse_smaps.ParseProcSmaps(device, process.pid)
executable_pss_kb, other_pss_kb = _GetPssInKb(
mappings, args.app_package, args.verbose)
total_executable_pss_kb += executable_pss_kb
total_other_pss_kb += other_pss_kb
print('Total executable PSS = %dkB' % total_executable_pss_kb)
print('Total other mappings PSS = %dkB' % total_other_pss_kb)
if __name__ == '__main__':
main()