def __init__(self, strPackageName): self.DEFAULT_ADDRESS = ("localhost", 5037) self.adb = Adb(self.DEFAULT_ADDRESS) self.strPackageName = strPackageName self.strUID = self.__get_UID() self.listProcessInfo = self.__init_processInfo() self.deviceAPILevel = self.__get_androidAPILevel()
def adb(): # Restart ADB adb = Adb(DEFAULT_ADDRESS) adb.kill() proc = AdbProcess("adb", DEFAULT_ADDRESS) proc.start() return adb
def __init__(self): ''' AndroidHandler构造函数 ''' self.__adb = Adb() self.__devices_list = self.__getConnection() if len(self.__devices_list) == 0: raise NoDeviceConnectionException self.__get_system_properties()
class AndroidHandler(): '''android系统及设备相关功能实现''' def __init__(self): ''' AndroidHandler构造函数 ''' self.__adb = Adb() self.__devices_list = self.__getConnection() if len(self.__devices_list) == 0: raise NoDeviceConnectionException self.__get_system_properties() def __getConnection(self): ''' 获取设备连接状态 :return: 连接的设备列表 ''' __ret_device_list = [] try: __devices_list = self.__adb.devices() except Exception, e: print str(e) raise ADBServerException if len(__devices_list) == 0: pass else: for __dev in __devices_list: if not __dev[1] == 'device': raise DeviceStatuException __ret_device_list.append(__dev) return __ret_device_list
def __init__(self,strPackageName): self.DEFAULT_ADDRESS = ("localhost",5037) self.adb = Adb(self.DEFAULT_ADDRESS) self.strPackageName = strPackageName self.strUID = self.__get_UID() self.listProcessInfo = self.__init_processInfo() self.deviceAPILevel = self.__get_androidAPILevel()
def __init__(self): ''' AndroidHandler构造函数 ''' if self._adb == None: self._adb = Adb()
class AndroidHandler(): '''android系统及设备相关功能实现''' DISPLAY_SIZE = (480, 600) _adb = None def __init__(self): ''' AndroidHandler构造函数 ''' if self._adb == None: self._adb = Adb() def getConnection(self): ''' 获取设备连接状态 :return: 连接的设备列表 ''' __ret_device_list = [] __devices_list = self._adb.devices() if len(__devices_list) == 0: pass else: for _dev in __devices_list: __ret_device_list.append(_dev[0]) return __ret_device_list def shell(self, cmd, serial=None, timeout=None): ''' 运行设备端命令 :param shell_cmd: 命令 :param timeout: 超时时间,默认无 :return: 命令运行返回值 ''' if serial == None: _cmd = str(cmd) _retVal = self._adb.shell(cmd, timeout=timeout) else: _retVal = self._adb.shell(cmd, serial, timeout=timeout) # with self._adb.socket.Connect(): # print self._adb.socket.address # # _cmd = host_command(serial, cmd) # # _cmd = 'host:get-serialno' # # _cmd = 'host:devices' # # _cmd = 'host: -s 4d0088254b015125 shell ls' # _cmd = 'host-serial:4d0088254b015125: uninstall com.gfth.coouj' # print _cmd # _retVal = self._adb._command(_cmd) return _retVal def getDevicesInfo(self): ''' 获取设备信息 :return: 设备信息字典 ''' __device_info_dic = {} __device_info = self.shell('getprop').replace('\n', '').split('\r') # __device_info = self.shell('getprop') print __device_info for __prop in __device_info: if __prop.count(':') > 0: try: # print("split prop: %s" % __prop) __prop_key = str(__prop).split(u'[')[1].split(u']')[0] __prop_value = str(__prop).split(u'[')[2][0:-1] # __prop_value = str(__prop).split(u':')[1] except: print "split prop %s exception" % str(__prop) else: continue if __prop_key == 'dalvik.vm.heapsize': print __prop __device_info_dic[DEV_INFO.DEVICES_HEAPSIZE] = __prop_value Logger.d("Get DEVICES_HEAPSIZE = " + __device_info_dic[DEV_INFO.DEVICES_HEAPSIZE]) if __prop_key == 'ro.build.version.release': __device_info_dic[DEV_INFO.DEVICES_AND_VERSION] = __prop_value Logger.d("Get DEVICES_AND _VERSION = " + __device_info_dic[DEV_INFO.DEVICES_AND_VERSION]) if __prop_key == 'ro.build.version.sdk': __device_info_dic[DEV_INFO.DEVICES_SDK_VERSION] = __prop_value Logger.d("Get DEVICES_SDK_VERSION = " + __device_info_dic[DEV_INFO.DEVICES_SDK_VERSION]) if __prop_key == 'ro.product.cpu.abi': __device_info_dic[DEV_INFO.DEVICES_CPU_TYPE] = __prop_value Logger.d("Get DEVICES_CPU_TYPE = " + __device_info_dic[DEV_INFO.DEVICES_CPU_TYPE]) if __prop_key == 'ro.product.manufacturer': devices_n1 = __prop_value if __prop_key == 'ro.product.model': devices_n2 = __prop_value try: __dev_name = str(devices_n1 + '-' + devices_n2).replace(' ', '-') __device_info_dic[DEV_INFO.DEVICES_NAME] = __dev_name Logger.d("Get DEVICES_NAME = " + __device_info_dic[DEV_INFO.DEVICES_NAME]) except Exception, e: print "Get device name error" #获取显示信息 try: __device_info_dic[DEV_INFO.DEVICES_DISP_SIZE] = self.getDisSize() except Exception, e: print "Get device display error"
def test_get_devices(self): ############################## # 1. 获取ABDpy实例 # #1. 获取ADBpy实例 __adbpy = Adb() ############################# # 2. 获取PID_LIST # #2.1. 运行设备端命令: ps | grep taobao, 获取淘宝相关进程PID命令原始返回字符串 __retval_1 = __adbpy.shell("ps | grep taobao") # print "Org_str: \t" + __retval_1 #2.2 将命令返回原始字符串,按行拆分为PID数据记录 __pid_list = __retval_1.split("\n") # print "PID List: %s : %s" % (type(__pid_list), __pid_list) #2.3 遍历pid列表,获取每一个PID记录中的PID值 #2.4 定义一个列表容器,去存储获取的PID值 __pids = [] #2.5 遍历PID数据记录列表中的PID数据 for __pid in __pid_list: #2.5.1 如果PID数据的长度<5个字符,则无效 if len(__pid) < 5: pass #2.5.2 如果为有效数据,则按" "拆分,获取其中的第4个元素,即PID的值,存储至__pids容器里 else: __pid = __pid.split(" ")[3] __pids.append(__pid) print("[INFO]PID_LIST= %s" % __pids) ############################# # 3. 获取PID_PSS # # 获取PIDs容器中的每一个PID对应的PSS TOTAL值 #3.1. 定义一个容器,用来存储 Tupple->(PID,PSS) __pid_pss_info = [] #3.2. 遍历pid,获取每一个pid对应的PSS Tupple数据 for __pid in __pids: # print "__pid = " + __pid #3.2.1 使用dumpsys meminfo ${pid}这个命令,获取原始的返回值 __returnValue = __adbpy.shell("dumpsys meminfo %s" % __pid) #3.2.2 将原始的命令返回值,按行拆分成可以处理的信息 __pid_mem_info = __returnValue.split('\n') # print "__pid info = %s" % __pid_mem_info #3.2.3 遍历每一信息,根据标记位获取PSS TOTAL值 for i in range(len(__pid_mem_info)): #3.2.3.1 如果这行信息中还有,标记"Unkonwn",则他的下一行是目标行 if __pid_mem_info[i].count("Unknown"): # print "Total: %s" % __pid_mem_info[i+1] #3.2.3.2 获取标记Unkonwn行的下一行 __pss_info = __pid_mem_info[i+1] #3.2.3.3 使用自定义的mem数据拆分方法进行pss info行数据的拆分,拆分后的第2个数值为PSS值 __pss = self.split_memRec(__pss_info)[1] # print "PSS = %s" % __pss #3.2.3.4 将当前PID与PSS值,组合成tuplle数据,存入__pid_pss_info数据结构中 __pid_pss_info.append((__pid,__pss)) #完成类所有PID及其对应的PSS值的获取 print ('[INFO] PID_PSS = %s' %__pid_pss_info) ############################# # 4. 计算AUT PSS总占用值 # # 获取PIDs容器中的每一个PID对应的PSS TOTAL值 #进行AUT 总PSS占用的计算 #4.1. 先定义一个变量,记录总PSS值 __total_pss = 0 #4.2. 遍历PSS INFO列表中的每一个PID_PSS Tupple数据 for __pss in __pid_pss_info: #2.1 获取Tuplle中的PSS值,下标为[1],进行累加 __total_pss += int(__pss[1]) #4.3. 获取类AUT 总PSS占用 print("[INFO] AUT_PSS = %s" % __total_pss)
def adb(): adb = Adb(()) adb.socket = MagicMock() return adb
def test_get_transport(): assert Adb._get_transport(Target.ANY) == "host:transport-any" assert Adb._get_transport(Target.USB) == "host:transport-usb" assert Adb._get_transport(Target.EMULATOR) == "host:transport-local" assert Adb._get_transport("950a8ad5") == "host:transport:950a8ad5"
def num_devices(): if adb_active(): a = Adb(DEFAULT_ADDRESS) return len(a.devices())
class AndroidHandler(): '''android系统及设备相关功能实现''' DISPLAY_SIZE = (480, 600) _adb = None def __init__(self): ''' AndroidHandler构造函数 ''' if self._adb == None: self._adb = Adb() def getConnection(self): ''' 获取设备连接状态 :return: 连接的设备列表 ''' __ret_device_list = [] __devices_list = self._adb.devices() if len(__devices_list) == 0: pass else: for _dev in __devices_list: __ret_device_list.append(_dev[0]) return __ret_device_list def shell(self, cmd, serial=None, timeout=None): ''' 运行设备端命令 :param shell_cmd: 命令 :param timeout: 超时时间,默认无 :return: 命令运行返回值 ''' if serial == None: _cmd = str(cmd) _retVal = self._adb.shell(cmd, timeout=timeout) else: _retVal = self._adb.shell(cmd, serial, timeout=timeout) # with self._adb.socket.Connect(): # print self._adb.socket.address # # _cmd = host_command(serial, cmd) # # _cmd = 'host:get-serialno' # # _cmd = 'host:devices' # # _cmd = 'host: -s 4d0088254b015125 shell ls' # _cmd = 'host-serial:4d0088254b015125: uninstall com.gfth.coouj' # print _cmd # _retVal = self._adb._command(_cmd) return _retVal def getDevicesInfo(self): ''' 获取设备信息 :return: 设备信息字典 ''' __device_info_dic = {} __device_info = self.shell('getprop').replace('\n','').split('\r') # __device_info = self.shell('getprop') print __device_info for __prop in __device_info: if __prop.count(':') > 0: try: # print("split prop: %s" % __prop) __prop_key = str(__prop).split(u'[')[1].split(u']')[0] __prop_value = str(__prop).split(u'[')[2][0:-1] # __prop_value = str(__prop).split(u':')[1] except: print "split prop %s exception" % str(__prop) else: continue if __prop_key == 'dalvik.vm.heapsize': print __prop __device_info_dic[DEV_INFO.DEVICES_HEAPSIZE] = __prop_value Logger.d("Get DEVICES_HEAPSIZE = " + __device_info_dic[DEV_INFO.DEVICES_HEAPSIZE]) if __prop_key == 'ro.build.version.release': __device_info_dic[DEV_INFO.DEVICES_AND_VERSION] = __prop_value Logger.d("Get DEVICES_AND _VERSION = " + __device_info_dic[DEV_INFO.DEVICES_AND_VERSION]) if __prop_key == 'ro.build.version.sdk': __device_info_dic[DEV_INFO.DEVICES_SDK_VERSION] = __prop_value Logger.d("Get DEVICES_SDK_VERSION = " + __device_info_dic[DEV_INFO.DEVICES_SDK_VERSION]) if __prop_key == 'ro.product.cpu.abi': __device_info_dic[DEV_INFO.DEVICES_CPU_TYPE] = __prop_value Logger.d("Get DEVICES_CPU_TYPE = " + __device_info_dic[DEV_INFO.DEVICES_CPU_TYPE]) if __prop_key == 'ro.product.manufacturer': devices_n1 = __prop_value if __prop_key == 'ro.product.model': devices_n2 = __prop_value try: __dev_name = str(devices_n1 + '-' + devices_n2).replace(' ','-') __device_info_dic[DEV_INFO.DEVICES_NAME] = __dev_name Logger.d("Get DEVICES_NAME = " + __device_info_dic[DEV_INFO.DEVICES_NAME]) except Exception, e: print "Get device name error" #获取显示信息 try: __device_info_dic[DEV_INFO.DEVICES_DISP_SIZE] = self.getDisSize() except Exception, e: print "Get device display error"
class AppUnderTest(object): """APP对象,需要传入App的包名作为参数来初始化""" def __init__(self, strPackageName): self.DEFAULT_ADDRESS = ("localhost", 5037) self.adb = Adb(self.DEFAULT_ADDRESS) self.strPackageName = strPackageName self.strUID = self.__get_UID() self.listProcessInfo = self.__init_processInfo() self.deviceAPILevel = self.__get_androidAPILevel() def __sizeof__(self): return super(AppUnderTest, self).__sizeof__() def __get_androidAPILevel(self): """获取手机上androidAPILevel的方法,用于处理dumpsys meminfo的分支判断""" APILevel = self.adb.shell('getprop ro.build.version.sdk', timeout=ADB_TIMEOUT) return int(APILevel) def __get_UID(self): """#获取App的UID的方法""" strTemp = self.adb.shell( 'dumpsys package "{0}"|{1} grep userId'.format( self.strPackageName, BUSYBOX_PATH), timeout=ADB_TIMEOUT) strUID = strTemp[11:16].strip( ) #切片返回字符串的第11到15个字符,即被测软件包的uid,形如"10086" if len(strUID) > 0: return strUID else: raise SystemExit("Cannot get the userID...stopped!!") def __init_processInfo(self): """#获取app进程及其子进程的processName和PID列表的方法. 返回二维的list,list[n][0]为第n个进程的PID,list[n][1]为其进程名""" strTemp = self.adb.shell("{0} top -bn 1|{0} grep '{1}'".format( BUSYBOX_PATH, self.strPackageName), timeout=ADB_TIMEOUT) listTemp = [ elem.split() for elem in strTemp.splitlines() if elem.find('busybox') == -1 ] #将得到的返回数据分行并分割成单词list,滤出不包含'busybox'字样的行 if len(listTemp) != 0: listProcessInfo = [ [elem[0], elem[-1]] for elem in listTemp ] #取listTemp中每个子list的的第一个和最后一个元素组成listProcessInfo,对应PID和processName listProcessInfo.sort(key=lambda x: x[ 1]) #对列表中第二个关键字也就是进程名进行排序,保证主进程所在的子list是listProcessInfo的第0个元素 else: raise SystemExit("App's process is not found!") print '[Debug]:ProcessInfo\n', listProcessInfo return listProcessInfo def __update_processInfo(self, listOutputOfTop): if len(listOutputOfTop) != 0: listProcessInfo = [ [elem[0], elem[-1]] for elem in listOutputOfTop ] #取listTemp中每个子list的的第一个和最后一个元素组成listProcessInfo,对应PID和processName listProcessInfo.sort(key=lambda x: x[ 1]) #对列表中第二个关键字也就是进程名进行排序,保证主进程所在的子list是listProcessInfo的第0个元素 else: raise SystemExit("App's process is not found!") if cmp(listProcessInfo, self.listProcessInfo) != 0: if len(listProcessInfo) > len(self.listProcessInfo): tempList = [ elem for elem in listProcessInfo if elem not in self.listProcessInfo ] self.listProcessInfo.extend(tempList) # print '[debug]---',tempList raise myUtil.FoundNewProcessException elif len(listProcessInfo) == len(self.listProcessInfo): tempList = [ elem for elem in listProcessInfo if elem not in self.listProcessInfo ] for elem in tempList: flag = 'Not_Found' for i, process in enumerate(self.listProcessInfo): if elem[1] in process: process[0] = elem[0] self.listProcessInfo[i] = process flag = 'Found' if flag == 'Not_Found': self.listProcessInfo.append(elem) raise myUtil.ProcessChangedException else: pass def get_networkTraffic(self): """#基于UID获取App的网络流量的方法 modify by oscar@easou,从/proc/net/xt_qtaguid/stats获取网络流量统计,先进行判断存在使用它,不存在使用之前的方法。 """ flag_net = self.adb.shell( '{0} cat /proc/net/xt_qtaguid/stats'.format(BUSYBOX_PATH), timeout=ADB_TIMEOUT) # print flag_net if "No such file or directory" not in flag_net: list_rx = [] # 接收网络数据流量列表 list_tx = [] # 发送网络数据流量列表 str_uid_net_stats = self.adb.shell( '{0} cat /proc/net/xt_qtaguid/stats|{0} grep {1}'.format( BUSYBOX_PATH, self.strUID), timeout=ADB_TIMEOUT) # print str_uid_net_stats try: for item in str_uid_net_stats.splitlines(): rx_bytes = item.split()[5] # 接收网络数据流量 tx_bytes = item.split()[7] # 发送网络数据流量 list_rx.append(int(rx_bytes)) list_tx.append(int(tx_bytes)) # print list_rx, sum(list_rx) floatTotalNetTraffic = (sum(list_rx) + sum(list_tx)) / 1024.0 / 1024.0 floatTotalNetTraffic = round(floatTotalNetTraffic, 4) return floatTotalNetTraffic except: print "[ERROR]: cannot get the /proc/net/xt_qtaguid/stats, return 0.0" return 0.0 else: strTotalTxBytes = self.adb.shell( '{0} cat /proc/uid_stat/{1}/tcp_snd'.format( BUSYBOX_PATH, self.strUID), timeout=ADB_TIMEOUT) strTotalRxBytes = self.adb.shell( '{0} cat /proc/uid_stat/{1}/tcp_rcv'.format( BUSYBOX_PATH, self.strUID), timeout=ADB_TIMEOUT) try: floatTotalTraffic = (int(strTotalTxBytes) + int(strTotalRxBytes)) / 1024.0 / 1024.0 floatTotalTraffic = round(floatTotalTraffic, 4) return floatTotalTraffic except: return 0.0 #捕获获取网络流量时的错误并一律视为流量是0(一般是因为被测App无任何网络活动,未在/proc/uid_stat/下生成对应其uid的目录) def get_procCPULoad_viaTop(self): """#基于listProcessInfo中每个子进程的PID,处理top命令的返回信息来获取所有子进程的CPU占用的方法""" listProcCPULoad = [] strTemp = self.adb.shell( "{0} top -bn 1|{0} grep {1}".format(BUSYBOX_PATH, self.strPackageName), timeout=ADB_TIMEOUT) #返回top命令输出中第一个元素为目标进程PID的一行 #listTemp = [elem.split() for elem in strTemp.split('\r\n')] listTemp = [ elem.split() for elem in strTemp.splitlines() if elem.find('busybox') == -1 ] self.__update_processInfo( listTemp) #调用此方法检查当前进程信息,如发生变化则抛出异常,由main()里的主循环异常处理函数处理 for elemOfProcessInfo in self.listProcessInfo: flag_Found = False for elem in listTemp: if (elem != []) and (elem[0] == elemOfProcessInfo[0]): if elem[4] == '<': strSubProcCPULoad = elem[ 7 + 1] #有些进程top命令返回信息里stat列是"s <"的形式中间有个空格会被当作分隔符,此时split()后的list里CPULoad对应值的下标得往后一位 listProcCPULoad.append(float(strSubProcCPULoad)) else: strSubProcCPULoad = elem[7] listProcCPULoad.append(float(strSubProcCPULoad)) flag_Found = True break if flag_Found == False: listProcCPULoad.append(0.0) return listProcCPULoad def get_procMemUsage(self): """#基于listProcessInfo,获取所有子进程内存占用PSS值的方法""" listProcMemUsage = [] if self.deviceAPILevel >= 14: #安卓4.0及上的,用这种逻辑 for elem in self.listProcessInfo: print '[Debug]:ProcessID---', elem[0] strTemp = self.adb.shell( "dumpsys meminfo {0}|{1} grep 'TOTAL'".format( elem[0], BUSYBOX_PATH), timeout=ADB_TIMEOUT) try: strSubProcMemUsage = strTemp.split()[1].encode('UTF-8') except IndexError: currentOutput = self.adb.shell( "dumpsys meminfo {0}".format(elem[0]), timeout=ADB_TIMEOUT) if currentOutput.find( 'No process found') != -1: #如果不等于-1则表明找到了这段string strSubProcMemUsage = 0.0 else: print 'Met an unhandled IndexError. Received this output "{0}" While getting MemUsage of process "{1}"'.format( strTemp, elem[1]) print 'Current device output when executing "dumpsys meminfo {} is:'.format( elem[1]), currentOutput raise listProcMemUsage.append( round(int(strSubProcMemUsage) / 1024.0, 4)) return listProcMemUsage else: #安卓4.0以下的,用这种逻辑 for elem in self.listProcessInfo: strTemp = self.adb.shell( "dumpsys meminfo {0}|{1} grep '(Pss)'".format( elem[0], BUSYBOX_PATH), timeout=ADB_TIMEOUT) try: strSubProcMemUsage = strTemp.split()[4].encode('UTF-8') except IndexError: currentOutput = self.adb.shell( "dumpsys meminfo {0}".format(elem[0]), timeout=ADB_TIMEOUT) if currentOutput.find( 'No process found') != -1: #如果不等于-1则表明找到了这段string strSubProcMemUsage = 0.0 else: print 'Met an unhandled IndexError. Received this output "{0}" While getting MemUsage of process "{1}"'.format( strTemp, elem[1]) print 'Current devices output when executing "dumpsys meminfo {} is:'.format( elem[1]), currentOutput raise listProcMemUsage.append( round(int(strSubProcMemUsage) / 1024.0, 4)) return listProcMemUsage def collect_allPerfInfo(self): """#将获取的数据汇总处理为中间数据的方法,每运行一次相当于一次采样. 返回一维List:设备时间戳、流量、各子进程的CPUload和MemUsage""" strCurrentTime = self.adb.shell(r"date +%s", timeout=ADB_TIMEOUT).replace( "\r\n", "").encode('UTF-8') strCurrentTraffic = self.get_networkTraffic() listEachProcCPULoad = self.get_procCPULoad_viaTop() listEachProcMemUsage = self.get_procMemUsage() floatTotalCPULoad = round(sum(listEachProcCPULoad), 4) floatTotalMemUsage = round(sum(listEachProcMemUsage), 4) listAllPerfInfo = [ strCurrentTime, strCurrentTraffic, floatTotalCPULoad, floatTotalMemUsage ] for x in xrange( len(listEachProcCPULoad) ): #循环遍历listEachProcCPULoad和listEachProcMemUsage,追加到listAllPerfInfo里 listAllPerfInfo.append(listEachProcCPULoad[x]) listAllPerfInfo.append(listEachProcMemUsage[x]) #将执行一次此方法所收集到的性能数据list以更加可读的形式在控制台打印出来 listForPrinting = [elem for elem in listAllPerfInfo] listForPrinting[0] = myUtil.seconds2Str(int(listAllPerfInfo[0])) print listForPrinting return listAllPerfInfo
def test_get_devices(self): ############################## # 1. 获取ABDpy实例 # #1. 获取ADBpy实例 __adbpy = Adb() ############################# # 2. 获取PID_LIST # #2.1. 运行设备端命令: ps | grep taobao, 获取淘宝相关进程PID命令原始返回字符串 __retval_1 = __adbpy.shell("ps | grep taobao") # print "Org_str: \t" + __retval_1 #2.2 将命令返回原始字符串,按行拆分为PID数据记录 __pid_list = __retval_1.split("\n") # print "PID List: %s : %s" % (type(__pid_list), __pid_list) #2.3 遍历pid列表,获取每一个PID记录中的PID值 #2.4 定义一个列表容器,去存储获取的PID值 __pids = [] #2.5 遍历PID数据记录列表中的PID数据 for __pid in __pid_list: #2.5.1 如果PID数据的长度<5个字符,则无效 if len(__pid) < 5: pass #2.5.2 如果为有效数据,则按" "拆分,获取其中的第4个元素,即PID的值,存储至__pids容器里 else: __pid = __pid.split(" ")[3] __pids.append(__pid) print("[INFO]PID_LIST= %s" % __pids) ############################# # 3. 获取PID_PSS # # 获取PIDs容器中的每一个PID对应的PSS TOTAL值 #3.1. 定义一个容器,用来存储 Tupple->(PID,PSS) __pid_pss_info = [] #3.2. 遍历pid,获取每一个pid对应的PSS Tupple数据 for __pid in __pids: # print "__pid = " + __pid #3.2.1 使用dumpsys meminfo ${pid}这个命令,获取原始的返回值 __returnValue = __adbpy.shell("dumpsys meminfo %s" % __pid) #3.2.2 将原始的命令返回值,按行拆分成可以处理的信息 __pid_mem_info = __returnValue.split('\n') # print "__pid info = %s" % __pid_mem_info #3.2.3 遍历每一信息,根据标记位获取PSS TOTAL值 for i in range(len(__pid_mem_info)): #3.2.3.1 如果这行信息中还有,标记"Unkonwn",则他的下一行是目标行 if __pid_mem_info[i].count("Unknown"): # print "Total: %s" % __pid_mem_info[i+1] #3.2.3.2 获取标记Unkonwn行的下一行 __pss_info = __pid_mem_info[i + 1] #3.2.3.3 使用自定义的mem数据拆分方法进行pss info行数据的拆分,拆分后的第2个数值为PSS值 __pss = self.split_memRec(__pss_info)[1] # print "PSS = %s" % __pss #3.2.3.4 将当前PID与PSS值,组合成tuplle数据,存入__pid_pss_info数据结构中 __pid_pss_info.append((__pid, __pss)) #完成类所有PID及其对应的PSS值的获取 print('[INFO] PID_PSS = %s' % __pid_pss_info) ############################# # 4. 计算AUT PSS总占用值 # # 获取PIDs容器中的每一个PID对应的PSS TOTAL值 #进行AUT 总PSS占用的计算 #4.1. 先定义一个变量,记录总PSS值 __total_pss = 0 #4.2. 遍历PSS INFO列表中的每一个PID_PSS Tupple数据 for __pss in __pid_pss_info: #2.1 获取Tuplle中的PSS值,下标为[1],进行累加 __total_pss += int(__pss[1]) #4.3. 获取类AUT 总PSS占用 print("[INFO] AUT_PSS = %s" % __total_pss)
class AppUnderTest(object): def __init__(self, strPackageName): self.DEFAULT_ADDRESS = ("localhost", 5037) self.adb = Adb(self.DEFAULT_ADDRESS) self.strPackageName = strPackageName self.strUID = self.__get_UID() self.listProcessInfo = self.__init_processInfo() def __sizeof__(self): return super(AppUnderTest, self).__sizeof__() def __get_UID(self): strTemp = self.adb.shell('dumpsys package "{0}"|grep userId'.format( self.strPackageName), timeout=ADB_TIMEOUT) strUID = strTemp[11:16].strip() return strUID def __init_processInfo(self): strTemp = self.adb.shell("{0} top -bn 1|grep '{1}'".format( BUSYBOX_PATH, self.strPackageName), timeout=ADB_TIMEOUT) listTemp = [ elem.split() for elem in strTemp.splitlines() if elem.find('grep') == -1 ] if len(listTemp) != 0: listProcessInfo = [[elem[0], elem[-1]] for elem in listTemp] listProcessInfo.sort(key=lambda x: x[1]) else: raise SystemExit("Processo não encontrado") print '[Debug]:ProcessInfo\n', listProcessInfo return listProcessInfo def __update_processInfo(self, listOutputOfTop): if len(listOutputOfTop) != 0: listProcessInfo = [[elem[0], elem[-1]] for elem in listOutputOfTop] listProcessInfo.sort(key=lambda x: x[1]) else: raise SystemExit("Processo não encontrado") if cmp(listProcessInfo, self.listProcessInfo) != 0: if len(listProcessInfo) > len(self.listProcessInfo): tempList = [ elem for elem in listProcessInfo if elem not in self.listProcessInfo ] self.listProcessInfo.extend(tempList) raise myUtil.FoundNewProcessException elif len(listProcessInfo) == len(self.listProcessInfo): tempList = [ elem for elem in listProcessInfo if elem not in self.listProcessInfo ] for elem in tempList: flag = 'Not_Found' for i, process in enumerate(self.listProcessInfo): if elem[1] in process: process[0] = elem[0] self.listProcessInfo[i] = process flag = 'Found' if flag == 'Not_Found': self.listProcessInfo.append(elem) raise myUtil.ProcessChangedException else: pass def get_networkTraffic(self): flag_net = self.adb.shell('cat /proc/net/xt_qtaguid/stats', timeout=ADB_TIMEOUT) if "No such file or directory" not in flag_net: list_rx = [] list_tx = [] str_uid_net_stats = self.adb.shell( 'cat /proc/net/xt_qtaguid/stats|grep {0}'.format(self.strUID), timeout=ADB_TIMEOUT) try: for item in str_uid_net_stats.splitlines(): rx_bytes = item.split()[5] tx_bytes = item.split()[7] list_rx.append(int(rx_bytes)) list_tx.append(int(tx_bytes)) # print list_rx, sum(list_rx) floatTotalNetTraffic = (sum(list_rx) + sum(list_tx)) / 1024.0 / 1024.0 floatTotalNetTraffic = round(floatTotalNetTraffic, 4) return floatTotalNetTraffic except: print "[ERROR]: Falha ao ler uso da rede, return 0.0" return 0.0 else: strTotalTxBytes = self.adb.shell( 'cat /proc/uid_stat/{0}/tcp_snd'.format(self.strUID), timeout=ADB_TIMEOUT) strTotalRxBytes = self.adb.shell( 'cat /proc/uid_stat/{0}/tcp_rcv'.format(self.strUID), timeout=ADB_TIMEOUT) try: floatTotalTraffic = (int(strTotalTxBytes) + int(strTotalRxBytes)) / 1024.0 / 1024.0 floatTotalTraffic = round(floatTotalTraffic, 4) return floatTotalTraffic except: return 0.0 def get_procCPULoad(self): listProcCPULoad = [] strTemp = self.adb.shell("{0} top -bn 1|grep {1}".format( BUSYBOX_PATH, self.strPackageName), timeout=ADB_TIMEOUT) listTemp = [ elem.split() for elem in strTemp.splitlines() if elem.find('grep') == -1 ] self.__update_processInfo(listTemp) for elemOfProcessInfo in self.listProcessInfo: flag_Found = False for elem in listTemp: if (elem != []) and (elem[0] == elemOfProcessInfo[0]): if elem[4] == '<': strSubProcCPULoad = elem[7 + 1] listProcCPULoad.append(float(strSubProcCPULoad)) else: value = elem[7] strSubProcCPULoad = value.replace('%', '') listProcCPULoad.append(float(strSubProcCPULoad)) flag_Found = True break if flag_Found == False: listProcCPULoad.append(0.0) return listProcCPULoad def get_procMemUsage(self): listProcMemUsage = [] for elem in self.listProcessInfo: strTemp = self.adb.shell("dumpsys meminfo {0}|grep 'TOTAL'".format( elem[0]), timeout=ADB_TIMEOUT) try: strSubProcMemUsage = strTemp.split()[1].encode('UTF-8') except IndexError: currentOutput = self.adb.shell("dumpsys meminfo {0}".format( elem[0]), timeout=ADB_TIMEOUT) if currentOutput.find('No process found') != -1: strSubProcMemUsage = 0.0 else: raise listProcMemUsage.append(round(int(strSubProcMemUsage) / 1024.0, 4)) return listProcMemUsage def collect_allPerfInfo(self): strCurrentTime = myUtil.seconds2Str( int( self.adb.shell(r"date +%s", timeout=ADB_TIMEOUT).replace( "\r\n", "").encode('UTF-8'))) strCurrentTraffic = str(self.get_networkTraffic()).replace('.', ',') listEachProcCPULoad = self.get_procCPULoad() listEachProcMemUsage = self.get_procMemUsage() floatTotalCPULoad = str(round(sum(listEachProcCPULoad), 4)).replace('.', ',') floatTotalMemUsage = str(round(sum(listEachProcMemUsage), 4)).replace('.', ',') listAllPerfInfo = [ strCurrentTime, strCurrentTraffic, floatTotalCPULoad, floatTotalMemUsage ] for x in xrange(len(listEachProcCPULoad)): listAllPerfInfo.append( str(listEachProcCPULoad[x]).replace('.', ',')) listAllPerfInfo.append( str(listEachProcMemUsage[x]).replace('.', ',')) listForPrinting = [elem for elem in listAllPerfInfo] listForPrinting[0] = listAllPerfInfo[0] print listForPrinting return listAllPerfInfo
class AppUnderTest(object): """APP对象,需要传入App的包名作为参数来初始化""" def __init__(self,strPackageName): self.DEFAULT_ADDRESS = ("localhost",5037) self.adb = Adb(self.DEFAULT_ADDRESS) self.strPackageName = strPackageName self.strUID = self.__get_UID() self.listProcessInfo = self.__init_processInfo() self.deviceAPILevel = self.__get_androidAPILevel() def __sizeof__(self): return super(AppUnderTest, self).__sizeof__() def __get_androidAPILevel(self): """获取手机上androidAPILevel的方法,用于处理dumpsys meminfo的分支判断""" APILevel = self.adb.shell('getprop ro.build.version.sdk',timeout=ADB_TIMEOUT) return int(APILevel) def __get_UID(self): """#获取App的UID的方法""" strTemp = self.adb.shell('dumpsys package "{0}"|{1} grep userId'.format(self.strPackageName,BUSYBOX_PATH),timeout=ADB_TIMEOUT) strUID = strTemp[11:16].strip() #切片返回字符串的第11到15个字符,即被测软件包的uid,形如"10086" if len(strUID) > 0: return strUID else: raise SystemExit("Cannot get the userID...stopped!!") def __init_processInfo(self): """#获取app进程及其子进程的processName和PID列表的方法. 返回二维的list,list[n][0]为第n个进程的PID,list[n][1]为其进程名""" strTemp = self.adb.shell("{0} top -bn 1|{0} grep '{1}'".format(BUSYBOX_PATH,self.strPackageName),timeout=ADB_TIMEOUT) listTemp = [elem.split() for elem in strTemp.splitlines() if elem.find('busybox') == -1] #将得到的返回数据分行并分割成单词list,滤出不包含'busybox'字样的行 if len(listTemp)!=0: listProcessInfo = [[elem[0],elem[-1]] for elem in listTemp] #取listTemp中每个子list的的第一个和最后一个元素组成listProcessInfo,对应PID和processName listProcessInfo.sort(key=lambda x:x[1]) #对列表中第二个关键字也就是进程名进行排序,保证主进程所在的子list是listProcessInfo的第0个元素 else: raise SystemExit("App's process is not found!") print '[Debug]:ProcessInfo\n', listProcessInfo return listProcessInfo def __update_processInfo(self,listOutputOfTop): if len(listOutputOfTop)!=0: listProcessInfo = [[elem[0],elem[-1]] for elem in listOutputOfTop] #取listTemp中每个子list的的第一个和最后一个元素组成listProcessInfo,对应PID和processName listProcessInfo.sort(key=lambda x:x[1]) #对列表中第二个关键字也就是进程名进行排序,保证主进程所在的子list是listProcessInfo的第0个元素 else: raise SystemExit("App's process is not found!") if cmp(listProcessInfo,self.listProcessInfo) != 0: if len(listProcessInfo) > len(self.listProcessInfo): tempList = [elem for elem in listProcessInfo if elem not in self.listProcessInfo] self.listProcessInfo.extend(tempList) # print '[debug]---',tempList raise myUtil.FoundNewProcessException elif len(listProcessInfo) == len(self.listProcessInfo): tempList = [elem for elem in listProcessInfo if elem not in self.listProcessInfo] for elem in tempList: flag = 'Not_Found' for i,process in enumerate(self.listProcessInfo): if elem[1] in process: process[0] = elem[0] self.listProcessInfo[i] = process flag = 'Found' if flag == 'Not_Found': self.listProcessInfo.append(elem) raise myUtil.ProcessChangedException else: pass def get_networkTraffic(self): """#基于UID获取App的网络流量的方法 modify by oscar@easou,从/proc/net/xt_qtaguid/stats获取网络流量统计,先进行判断存在使用它,不存在使用之前的方法。 """ flag_net = self.adb.shell('{0} cat /proc/net/xt_qtaguid/stats'.format(BUSYBOX_PATH),timeout=ADB_TIMEOUT) # print flag_net if "No such file or directory" not in flag_net: list_rx = [] # 接收网络数据流量列表 list_tx = [] # 发送网络数据流量列表 str_uid_net_stats = self.adb.shell('{0} cat /proc/net/xt_qtaguid/stats|{0} grep {1}'.format(BUSYBOX_PATH,self.strUID),timeout=ADB_TIMEOUT) # print str_uid_net_stats try: for item in str_uid_net_stats.splitlines(): rx_bytes = item.split()[5] # 接收网络数据流量 tx_bytes = item.split()[7] # 发送网络数据流量 list_rx.append(int(rx_bytes)) list_tx.append(int(tx_bytes)) # print list_rx, sum(list_rx) floatTotalNetTraffic = (sum(list_rx) + sum(list_tx))/1024.0/1024.0 floatTotalNetTraffic = round(floatTotalNetTraffic,4) return floatTotalNetTraffic except: print "[ERROR]: cannot get the /proc/net/xt_qtaguid/stats, return 0.0" return 0.0 else: strTotalTxBytes = self.adb.shell('{0} cat /proc/uid_stat/{1}/tcp_snd'.format(BUSYBOX_PATH,self.strUID),timeout=ADB_TIMEOUT) strTotalRxBytes = self.adb.shell('{0} cat /proc/uid_stat/{1}/tcp_rcv'.format(BUSYBOX_PATH,self.strUID),timeout=ADB_TIMEOUT) try: floatTotalTraffic = (int(strTotalTxBytes) + int(strTotalRxBytes))/1024.0/1024.0 floatTotalTraffic = round(floatTotalTraffic,4) return floatTotalTraffic except: return 0.0 #捕获获取网络流量时的错误并一律视为流量是0(一般是因为被测App无任何网络活动,未在/proc/uid_stat/下生成对应其uid的目录) def get_procCPULoad_viaTop(self): """#基于listProcessInfo中每个子进程的PID,处理top命令的返回信息来获取所有子进程的CPU占用的方法""" listProcCPULoad = [] strTemp = self.adb.shell("{0} top -bn 1|{0} grep {1}".format(BUSYBOX_PATH,self.strPackageName),timeout=ADB_TIMEOUT) #返回top命令输出中第一个元素为目标进程PID的一行 #listTemp = [elem.split() for elem in strTemp.split('\r\n')] listTemp = [elem.split() for elem in strTemp.splitlines() if elem.find('busybox') == -1] self.__update_processInfo(listTemp) #调用此方法检查当前进程信息,如发生变化则抛出异常,由main()里的主循环异常处理函数处理 for elemOfProcessInfo in self.listProcessInfo: flag_Found = False for elem in listTemp: if (elem != []) and (elem[0] == elemOfProcessInfo[0]): if elem[4] == '<': strSubProcCPULoad = elem[7+1] #有些进程top命令返回信息里stat列是"s <"的形式中间有个空格会被当作分隔符,此时split()后的list里CPULoad对应值的下标得往后一位 listProcCPULoad.append(float(strSubProcCPULoad)) else: strSubProcCPULoad = elem[7] listProcCPULoad.append(float(strSubProcCPULoad)) flag_Found = True break if flag_Found == False: listProcCPULoad.append(0.0) return listProcCPULoad def get_procMemUsage(self): """#基于listProcessInfo,获取所有子进程内存占用PSS值的方法""" listProcMemUsage = [] if self.deviceAPILevel >= 14: #安卓4.0及上的,用这种逻辑 for elem in self.listProcessInfo: print '[Debug]:ProcessID---',elem[0] strTemp = self.adb.shell("dumpsys meminfo {0}|{1} grep 'TOTAL'".format(elem[0],BUSYBOX_PATH),timeout=ADB_TIMEOUT) try: strSubProcMemUsage = strTemp.split()[1].encode('UTF-8') except IndexError: currentOutput = self.adb.shell("dumpsys meminfo {0}".format(elem[0]),timeout=ADB_TIMEOUT) if currentOutput.find('No process found')!=-1: #如果不等于-1则表明找到了这段string strSubProcMemUsage = 0.0 else: print 'Met an unhandled IndexError. Received this output "{0}" While getting MemUsage of process "{1}"'.format(strTemp,elem[1]) print 'Current device output when executing "dumpsys meminfo {} is:'.format(elem[1]), currentOutput raise listProcMemUsage.append(round(int(strSubProcMemUsage)/1024.0,4)) return listProcMemUsage else: #安卓4.0以下的,用这种逻辑 for elem in self.listProcessInfo: strTemp = self.adb.shell("dumpsys meminfo {0}|{1} grep '(Pss)'".format(elem[0],BUSYBOX_PATH),timeout=ADB_TIMEOUT) try: strSubProcMemUsage = strTemp.split()[4].encode('UTF-8') except IndexError: currentOutput = self.adb.shell("dumpsys meminfo {0}".format(elem[0]),timeout=ADB_TIMEOUT) if currentOutput.find('No process found')!=-1: #如果不等于-1则表明找到了这段string strSubProcMemUsage = 0.0 else: print 'Met an unhandled IndexError. Received this output "{0}" While getting MemUsage of process "{1}"'.format(strTemp,elem[1]) print 'Current devices output when executing "dumpsys meminfo {} is:'.format(elem[1]), currentOutput raise listProcMemUsage.append(round(int(strSubProcMemUsage)/1024.0,4)) return listProcMemUsage def collect_allPerfInfo(self): """#将获取的数据汇总处理为中间数据的方法,每运行一次相当于一次采样. 返回一维List:设备时间戳、流量、各子进程的CPUload和MemUsage""" strCurrentTime = self.adb.shell(r"date +%s",timeout=ADB_TIMEOUT).replace("\r\n","").encode('UTF-8') strCurrentTraffic = self.get_networkTraffic() listEachProcCPULoad = self.get_procCPULoad_viaTop() listEachProcMemUsage = self.get_procMemUsage() floatTotalCPULoad = round(sum(listEachProcCPULoad),4) floatTotalMemUsage = round(sum(listEachProcMemUsage),4) listAllPerfInfo = [strCurrentTime,strCurrentTraffic,floatTotalCPULoad,floatTotalMemUsage] for x in xrange(len(listEachProcCPULoad)): #循环遍历listEachProcCPULoad和listEachProcMemUsage,追加到listAllPerfInfo里 listAllPerfInfo.append(listEachProcCPULoad[x]) listAllPerfInfo.append(listEachProcMemUsage[x]) #将执行一次此方法所收集到的性能数据list以更加可读的形式在控制台打印出来 listForPrinting = [elem for elem in listAllPerfInfo] listForPrinting[0] = myUtil.seconds2Str(int(listAllPerfInfo[0])) print listForPrinting return listAllPerfInfo