コード例 #1
0
class TestIterationData(object):

    def setUp(self):
        self.data = IterationData()
        self.data.uid_usage[2] = UsageData(10)

    def test_add(self):
        idata = IterationData()
        idata.uid_usage[2] = UsageData(10)
        idata.uid_usage[3] = UsageData(15)

        idata = self.data.add(idata)
        self.assertEqual(self.data.uid_usage.keys(), [2])
        self.assertEqual(self.data.uid_usage.values(), [UsageData(20)])
        self.assertEqual(idata.uid_usage.keys(), [2, 3])
        self.assertEqual(idata.uid_usage.values(), [UsageData(20),
            UsageData(15)])

    def test_add_uid_usage(self):
        self.data.add_uid_usage(10, UsageData(15))
        self.assertEqual(self.data.uid_usage[10].usage, 15)

    def test_set_usage(self):
        self.data.set_usage(10)
        self.assertEqual(self.uid_usage[SystemInfo.AID_ALL], 10)
コード例 #2
0
    def test_add(self):
        idata = IterationData()
        idata.uid_usage[2] = UsageData(10)
        idata.uid_usage[3] = UsageData(15)

        idata = self.data.add(idata)
        self.assertEqual(self.data.uid_usage.keys(), [2])
        self.assertEqual(self.data.uid_usage.values(), [UsageData(20)])
        self.assertEqual(idata.uid_usage.keys(), [2, 3])
        self.assertEqual(idata.uid_usage.values(), [UsageData(20),
            UsageData(15)])
コード例 #3
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using audio after one
        iteration. """
        result = IterationData()

        audio_on = (self._uid_usage is not None and len(self._uid_states) !=
                    0) or (self.AudioProxy.is_music_active())
        result.set_sys_usage(AudioUsage(audio_on))

        if self._uid_usage is not None:
            with self._uidstate_lock:
                uid = -1

                for usage in self._uid_usage.values():
                    if usage.uid != uid:
                        result.set_uid_usage(usage.proxy_uid, AudioUsage(True))
                    uid = usage.uid

        return result
コード例 #4
0
ファイル: lcd.py プロジェクト: mmartins/android-power-monitor
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using display after one
        iteration. """
        result = IterationData()

        brightness = Screen.get_display_brightness()

        if 0 <= brightness <= 255:
            self.logger.warn("Could not retrieve brightness information")
            return result

        with self._screenlock:
            screen = self.screen_on

        usage = LCDUsage(brightness, screen)
        result.set_sys_usage(usage)

        if screen:
            uid = ForegroundDetector.get_foreground_uid()
            result.set_uid_usage(uid, usage)

        return result
コード例 #5
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using display after one
        iteration. """
        result = IterationData()

        brightness = Screen.get_display_brightness()

        if 0 <= brightness <= 255:
            self.logger.warn("Could not retrieve brightness information")
            return result

        with self._screenlock:
            screen = self.screen_on

        px_pwr = 0.0

        # TODO: Substitute with C-based getScreenPixPower native function
        if screen and self._fb_file is not None:
            try:
                with open(self._fb_file) as fp:
                    for x in self._fb_samples:
                        fp.seek(x * 4)
                        # Read 32-bit integer from file
                        px = struct.unpack('i', fp.read(4))[0]
                        blue = px >> 8 & 0xFF
                        green = px >> 16 & 0xFF
                        red = px >> 24 & 0xFF

                        # Calculate the power usage of this pixel as if it were
                        # at full brightness. Linearly scale by brightness to
                        # get true power usage. To calculate whole screen power
                        # usage, compute average of sampled region and multiply
                        # by number of pixels

                        sum_colors = red + green + blue
                        px_pwr += (self.RED_PWR * (red*red) +
                                   self.GREEN_PWR * (green*green) +
                                   self.BLUE_PWR * (blue*blue) -
                                   self.MODULATION_PWR *
                                   (sum_colors * sum_colors))
            except IOError as (errno, strerr):
                self.logger.warn("Can't read framebuffer {0}".format(strerr))
                px_pwr = 0.0

            if px_pwr > 0.0:
                px_pwr *= self.width * self.height / self.NSAMPLES
コード例 #6
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using audio after one
        iteration. """
        result = IterationData()

        audio_on = (self._uid_usage is not None and len(self._uid_states) != 0
                    ) or (self.AudioProxy.is_music_active())
        result.set_sys_usage(AudioUsage(audio_on))

        if self._uid_usage is not None:
            with self._uidstate_lock:
                uid = -1

                for usage in self._uid_usage.values():
                    if usage.uid != uid:
                        result.set_uid_usage(usage.proxy_uid, AudioUsage(True))
                    uid = usage.uid

        return result
コード例 #7
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using sensors after one
        iteration. """
        result = IterationData()
        sensor_usage = SensorUsage()

        with self._sensorslock:
            sensor_usage.on_times = self._state.get_times()
            result.set_sys_usage(sensor_usage)

            for uid, state in self._uid_states.iteritems():
                usage = SensorUsage()
                usage.on_times = state.get_times()
                result.set_uid_usage(uid, usage)

                if state.started_sensors == 0:
                    del (self._uid_states[uid])

        return result
コード例 #8
0
ファイル: gps.py プロジェクト: mmartins/android-power-monitor
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using GPS after one
        iteration. """
        result = IterationData()

        # Get the power data for the physical GPS device

        with self._statekeeper_lock:
            state_times = self._statekeeper.state_times
            pwr_state = self._statekeeper.pwr_state
            self._statekeeper.reset_times()

        # Get the number of satellite that were available in the last update

        num_satellites = 0
        with self._gpsstatus_lock:
            if pwr_state == self.POWER_STATE_ON and self._status is not None:
                num_satellites = len(self._status.getSatellites())

        result.set_sys_usage(GPSUsage(state_times, num_satellites))

        # Get usage data for each UID we have information on
        if self.has_uid_information:
            with self._uidstates_lock:
                self._update_time = (self._start_time + self._iter_interval *
                                     iter_num)
                for uid, state in self._uid_states.iteritems():
                    state_times = state.get_state_times()
                    pwr_state = state.get_power_state()
                    state.reset_times()

                    # There is a guarantee that num_satellites will be zero
                    # if GPS is off (see above)
                    result.set_uid_usage(uid, GPSUsage(state_times,
                                                       num_satellites))

                    # Remove state information for UIDs no longer using the GPS
                    if pwr_state == self.POWER_STATE_OFF:
                        del (self._uid_states[uid])

        return result
コード例 #9
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using display after one
        iteration. """
        result = IterationData()

        brightness = Screen.get_display_brightness()

        if 0 <= brightness <= 255:
            self.logger.warn("Could not retrieve brightness information")
            return result

        with self._screenlock:
            screen = self.screen_on

        usage = LCDUsage(brightness, screen)
        result.set_sys_usage(usage)

        if screen:
            uid = ForegroundDetector.get_foreground_uid()
            result.set_uid_usage(uid, usage)

        return result
コード例 #10
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using WiFi after one
        iteration. """
        result = IterationData()

        state = self._wifi.get_state()

        if ((state != WifiAccess.WIFI_STATE_ENABLED) or
                (state != WifiAccess.WIFI_STATE_DISABLING)):
            # Allow the real interface state keeper to reset its state so that
            # the next update it knows it's coming back from an off state. We
            # also need to clear all UID information

            self._state.interface_off()
            self._uid_states.clear()
            self._speed = None

            result.set_sys_usage(WifiUsage())
            return result

        tx_pkts = int(self._sysfs.tx_packets)
        rx_pkts = int(self._sysfs.rx_packets)
        tx_bytes = int(self._sysfs.tx_bytes)
        rx_bytes = int(self._sysfs.rx_bytes)

        if ((tx_pkts == -1) or (rx_pkts == -1) or (tx_bytes == -1) or
                (rx_bytes == -1)):
            self.logger.warn("Failed to read packet and byte counts from WiFi")
            return result

        # Update the link speed every 15 seconds as pulling the WifiInfo
        # structure from WifiManager is a little expensive. This isn't really
        # something that is likely to change frequently anyway

        if (iter_num % 15 == 0) or not self._speed:
            self._speed = self._wifi.get_speed()

        if self._state.is_initialized():
            result.set_sys_usage(WifiUsage(True, self._state.delta_pkts,
                                           self._state.delta_tx_bytes,
                                           self._state.delta_rx_bytes,
                                           self._state.tx_rate, self._speed,
                                           self._state.pwr_state))

        self._state.update(tx_pkts, rx_pkts, tx_bytes, rx_bytes)

        uids = SystemInfo.get_uids()

        if uids is not None:
            for uid in uids:
                if uid < 0:
                    continue

                uid_state = self._uid_states.get(uid, None)

                if not uid_state:
                    uid_state = WifiState(self._constants.WIFI_HIGHLOW_PKTBOUND,
                                          self._constants.WIFI_LOWHIGH_PKTBOUND)
                    self._uid_states[uid] = uid_state

                if not uid_state.is_stale():
                    # Use heuristic to not poll for UIDs that haven't had much
                    # activity recently
                    continue

                # These read operations are the expensive part of polling
                with open(self.UID_TX_BYTE_MASK.format(uid)) as fp:
                    tx_bytes = int(fp.read().strip())
                with open(self.UID_RX_BYTE_MASK.format(uid)) as fp:
                    rx_bytes = int(fp.read().strip())

                if (rx_bytes == -1) or (tx_bytes == -1):
                    self.logger.warn("Failed to read UID Tx/Rx byte counts")
                elif uid_state.is_initialized():
                    # We only have info on bytes received but what we really
                    # want is the number of packets received so we will
                    # estimate it
                    delta_tx_bytes = tx_bytes - self._state.tx_bytes
                    delta_rx_bytes = rx_bytes - self._state.rx_bytes
                    tx_pkts = int(round(delta_tx_bytes /
                                        self._state.avg_tx_pkt_size))
                    rx_pkts = int(round(delta_rx_bytes /
                                        self._state.avg_rx_pkt_size))

                    if (delta_tx_bytes > 0) and (tx_pkts == 0):
                        tx_pkts = 1

                    if (delta_rx_bytes > 0) and (rx_pkts == 0):
                        rx_pkts = 1

                    active = ((tx_bytes != uid_state.tx_bytes) or
                              (rx_bytes != uid_state.rx_bytes))

                    uid_state.update((self._state.tx_pkts + tx_pkts),
                                     (self._state.rx_pkts + rx_pkts), tx_bytes,
                                     rx_bytes)

                    if active:
                        usage = WifiUsage(True, uid_state.delta_pkts,
                                          uid_state.delta_tx_bytes,
                                          uid_state.delta_rx_bytes,
                                          uid_state.tx_rate,
                                          self._speed, uid_state.pwr_state)
                        result.set_uid_usage(uid, usage)
                else:
                    uid_state.update(0, 0, tx_bytes, rx_bytes)

        return result
コード例 #11
0
ファイル: cpu.py プロジェクト: mmartins/android-power-monitor
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using CPU core after one
        iteration. """
        result = IterationData()

        freq = self._read_cpu_freq()

        if freq == 0:
            self.logger.warn("Failed to read CPU frequency")
            return result

        times = SystemInfo.get_usr_sys_total_times(self.num)

        if len(times) == 0:
            self.logger.warn("Failed to read CPU times")
            return result

        usr_time = times[SystemInfo.INDEX_USR_TIME]
        sys_time = times[SystemInfo.INDEX_SYS_TIME]
        total_time = times[SystemInfo.INDEX_TOTAL_TIME]

        init = self._state.is_initialized()
        self._state.update(usr_time, sys_time, total_time, iter_num)

        # Power draw is based on usage time along with CPU frequency
        if init:
            result.set_sys_usage(
                CPUUsage(self._state.get_usr_perc(),
                         self._state.get_sys_perc(), freq))

        # Distribute CPU power draw during iteration among running processes.
        # CPU usage is returned by Linux using process ID.
        # A UID can have many processes and our final result should be based on
        # UID (app), therefore we need to account for all processes referring
        # to the same UID
        self._uid_states.clear()
        pids = SystemInfo.get_running_pids()

        if pids is not None:
            for i, pid in enumerate(pids):
                if pid < 0:
                    break

                pid_state = self._pid_states.get(pid, None)

                # New process that hasn't been registered yet by our monitor
                if not pid_state:
                    uid = SystemInfo.get_uid_for_pid(pid)

                    if uid >= 0:
                        self._pid_states[pid] = CPUState(uid)
                    else:
                        # Assume process no longer exists
                        continue

                if pid_state.is_stale(iter_num):
                    # Nothing much is going on with this PID recently. We'll
                    # just assume that it's not using any of the CPU for this
                    # iteration
                    pid_state.skip_update(iter_num, total_time)
                else:
                    times = SystemInfo.get_pid_usr_sys_times(pid)

                    if len(times) > 0:
                        usr_time = times[SystemInfo.INDEX_USR_TIME]
                        sys_time = times[SystemInfo.INDEX_SYS_TIME]

                        # Update slice of time used by this process based on
                        # global iteration time
                        pid_state.update(usr_time, sys_time, total_time,
                                         iter_num)

                        if not init:
                            continue

                uid_state = self._uid_states.get(pid_state.uid, None)

                # Register new UID if it doesn't exist. Else absorb power data
                # from its respective process
                if uid_state is not None:
                    self._uid_states[pid_state.uid] = pid_state
                else:
                    uid_state.absorb(pid_state)

        # Remove processes that are no longer active
        self._pid_states = {
            k: v
            for k, v in self._pid_states.iteritems()
            if self._pid_states[k].is_alive(iter_num)
        }

        # Collect the summed UID information
        for k, v in self._uid_states.iteritems():
            uid_usage = self._get_cpu_usage(uid_state.get_usr_perc(),
                                            uid_state.get_sys_perc(), freq)
            result.set_uid_usage(uid, uid_usage)

        return result
コード例 #12
0
 def calc_iteration(self, iter_num):
     total = IterationData()
     # TODO: Rewrite below using FP
     for cpu in self.cpus:
         total.add(cpu.calc_iteration(iter_num))
     return total
コード例 #13
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using 3G interface during
        one iteration."""
        result = IterationData()

        net_type = self._telephony.get_network_type()

        # Seems like TelephonyManager.NETWORK_TYPE_HSDPA = 8
        # TODO: Actually get models for the different network types
        if ((net_type != TelephonyAccess.NETWORK_TYPE_UMTS) and
                (net_type != TelephonyAccess.NETWORK_TYPE_HSDPA)):
            net_type = TelephonyAccess.NETWORK_TYPE_UMTS

        net_state = self._telephony.get_state()
        if ((net_state != TelephonyAccess.DATA_CONNECTED) or
                (net_type != TelephonyAccess.NETWORK_TYPE_UMTS and net_type
                    != TelephonyAccess.NETWORK_TYPE_HSDPA)):
            # We need to allow the real interface state to reset itself so that
            # the next update it knows it's coming back from an off state. We
            # also need to clear all UID information
            self._state.interface_off()
            self._uid_states.clear()

            result.set_sys_usage(ThreeGUsage())

            return result

        tx_pkts = int(self._sysfs.tx_packets)
        rx_pkts = int(self._sysfs.rx_packets)
        tx_bytes = int(self._sysfs.tx_bytes)
        rx_bytes = int(self._sysfs.rx_bytes)

        if (tx_bytes == -1) or (rx_bytes == -1):
            self.logger.warn("Failed to read  UID Tx/Rx byte counts")
            return result
        self._state.update(tx_pkts, rx_pkts, tx_bytes, rx_bytes)

        if self._state.is_initialized():
            result.set_sys_usage(ThreeGUsage(True, self._state.delta_pkts,
                                             self._state.tx_bytes,
                                             self._state.rx_bytes,
                                             self._state.pwr_state,
                                             self._provider))

        uids = SystemInfo.get_uids()

        if uids is not None:
            for uid in uids:
                if uid < 0:
                    continue

                uid_state = self._uid_states.setdefault(uid, ThreeGState())

                if uid_state.is_stale():
                    # Use heuristic to not poll for UIDs that haven't had much
                    # activity recently
                    continue

                # Read operations are the expensive part of polling
                with open(self.UID_TX_BYTE_MASK.format(uid)) as fp:
                    tx_bytes = int(fp.read().strip())
                with open(self.UID_RX_BYTE_MASK.format(uid)) as fp:
                    rx_bytes = int(fp.read().strip())

                if (rx_bytes == -1) or (tx_bytes == -1):
                    self.logger.warn("Failed to read UID Tx/Rx byte counts")
                elif uid_state.is_initialized():
                    uid_state.update(0, 0, tx_bytes, rx_bytes)

                    if ((uid_state.tx_bytes + uid_state.rx_bytes != 0) or
                            (uid_state.pwr_state != self.POWER_STATE_IDLE)):
                        usage = ThreeGUsage(True, uid_state.delta_pkts,
                                            uid_state.tx_bytes,
                                            uid_state.rx_bytes,
                                            uid_state.pwr_state, self._provider)
                        result.set_uid_usage(uid, usage)
                else:
                    uid_state.update(0, 0, tx_bytes, rx_bytes)

        return result
コード例 #14
0
 def setUp(self):
     self.data = IterationData()
     self.data.uid_usage[2] = UsageData(10)
コード例 #15
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using 3G interface during
        one iteration."""
        result = IterationData()

        net_type = self._telephony.get_network_type()

        # Seems like TelephonyManager.NETWORK_TYPE_HSDPA = 8
        # TODO: Actually get models for the different network types
        if ((net_type != TelephonyAccess.NETWORK_TYPE_UMTS)
                and (net_type != TelephonyAccess.NETWORK_TYPE_HSDPA)):
            net_type = TelephonyAccess.NETWORK_TYPE_UMTS

        net_state = self._telephony.get_state()
        if ((net_state != TelephonyAccess.DATA_CONNECTED)
                or (net_type != TelephonyAccess.NETWORK_TYPE_UMTS
                    and net_type != TelephonyAccess.NETWORK_TYPE_HSDPA)):
            # We need to allow the real interface state to reset itself so that
            # the next update it knows it's coming back from an off state. We
            # also need to clear all UID information
            self._state.interface_off()
            self._uid_states.clear()

            result.set_sys_usage(ThreeGUsage())

            return result

        tx_pkts = int(self._sysfs.tx_packets)
        rx_pkts = int(self._sysfs.rx_packets)
        tx_bytes = int(self._sysfs.tx_bytes)
        rx_bytes = int(self._sysfs.rx_bytes)

        if (tx_bytes == -1) or (rx_bytes == -1):
            self.logger.warn("Failed to read  UID Tx/Rx byte counts")
            return result
        self._state.update(tx_pkts, rx_pkts, tx_bytes, rx_bytes)

        if self._state.is_initialized():
            result.set_sys_usage(
                ThreeGUsage(True, self._state.delta_pkts, self._state.tx_bytes,
                            self._state.rx_bytes, self._state.pwr_state,
                            self._provider))

        uids = SystemInfo.get_uids()

        if uids is not None:
            for uid in uids:
                if uid < 0:
                    continue

                uid_state = self._uid_states.setdefault(uid, ThreeGState())

                if uid_state.is_stale():
                    # Use heuristic to not poll for UIDs that haven't had much
                    # activity recently
                    continue

                # Read operations are the expensive part of polling
                with open(self.UID_TX_BYTE_MASK.format(uid)) as fp:
                    tx_bytes = int(fp.read().strip())
                with open(self.UID_RX_BYTE_MASK.format(uid)) as fp:
                    rx_bytes = int(fp.read().strip())

                if (rx_bytes == -1) or (tx_bytes == -1):
                    self.logger.warn("Failed to read UID Tx/Rx byte counts")
                elif uid_state.is_initialized():
                    uid_state.update(0, 0, tx_bytes, rx_bytes)

                    if ((uid_state.tx_bytes + uid_state.rx_bytes != 0)
                            or (uid_state.pwr_state != self.POWER_STATE_IDLE)):
                        usage = ThreeGUsage(True, uid_state.delta_pkts,
                                            uid_state.tx_bytes,
                                            uid_state.rx_bytes,
                                            uid_state.pwr_state,
                                            self._provider)
                        result.set_uid_usage(uid, usage)
                else:
                    uid_state.update(0, 0, tx_bytes, rx_bytes)

        return result
コード例 #16
0
ファイル: cpu.py プロジェクト: mmartins/android-power-monitor
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using CPU core after one
        iteration. """
        result = IterationData()

        freq = self._read_cpu_freq()

        if freq == 0:
            self.logger.warn("Failed to read CPU frequency")
            return result

        times = SystemInfo.get_usr_sys_total_times(self.num)

        if len(times) == 0:
            self.logger.warn("Failed to read CPU times")
            return result

        usr_time = times[SystemInfo.INDEX_USR_TIME]
        sys_time = times[SystemInfo.INDEX_SYS_TIME]
        total_time = times[SystemInfo.INDEX_TOTAL_TIME]

        init = self._state.is_initialized()
        self._state.update(usr_time, sys_time, total_time, iter_num)

        # Power draw is based on usage time along with CPU frequency
        if init:
            result.set_sys_usage(CPUUsage(self._state.get_usr_perc(),
                                          self._state.get_sys_perc(), freq))

        # Distribute CPU power draw during iteration among running processes.
        # CPU usage is returned by Linux using process ID.
        # A UID can have many processes and our final result should be based on
        # UID (app), therefore we need to account for all processes referring
        # to the same UID
        self._uid_states.clear()
        pids = SystemInfo.get_running_pids()

        if pids is not None:
            for i, pid in enumerate(pids):
                if pid < 0:
                    break

                pid_state = self._pid_states.get(pid, None)

                # New process that hasn't been registered yet by our monitor
                if not pid_state:
                    uid = SystemInfo.get_uid_for_pid(pid)

                    if uid >= 0:
                        self._pid_states[pid] = CPUState(uid)
                    else:
                        # Assume process no longer exists
                        continue

                if pid_state.is_stale(iter_num):
                    # Nothing much is going on with this PID recently. We'll
                    # just assume that it's not using any of the CPU for this
                    # iteration
                    pid_state.skip_update(iter_num, total_time)
                else:
                    times = SystemInfo.get_pid_usr_sys_times(pid)

                    if len(times) > 0:
                        usr_time = times[SystemInfo.INDEX_USR_TIME]
                        sys_time = times[SystemInfo.INDEX_SYS_TIME]

                        # Update slice of time used by this process based on
                        # global iteration time
                        pid_state.update(usr_time, sys_time, total_time,
                                         iter_num)

                        if not init:
                            continue

                uid_state = self._uid_states.get(pid_state.uid, None)

                # Register new UID if it doesn't exist. Else absorb power data
                # from its respective process
                if uid_state is not None:
                    self._uid_states[pid_state.uid] = pid_state
                else:
                    uid_state.absorb(pid_state)

        # Remove processes that are no longer active
        self._pid_states = {k: v for k, v in self._pid_states.iteritems() if
                            self._pid_states[k].is_alive(iter_num)}

        # Collect the summed UID information
        for k, v in self._uid_states.iteritems():
            uid_usage = self._get_cpu_usage(uid_state.get_usr_perc(),
                                            uid_state.get_sys_perc(), freq)
            result.set_uid_usage(uid, uid_usage)

        return result
コード例 #17
0
    def calc_iteration(self, iter_num):
        """ Return power usage of each application using WiFi after one
        iteration. """
        result = IterationData()

        state = self._wifi.get_state()

        if ((state != WifiAccess.WIFI_STATE_ENABLED)
                or (state != WifiAccess.WIFI_STATE_DISABLING)):
            # Allow the real interface state keeper to reset its state so that
            # the next update it knows it's coming back from an off state. We
            # also need to clear all UID information

            self._state.interface_off()
            self._uid_states.clear()
            self._speed = None

            result.set_sys_usage(WifiUsage())
            return result

        tx_pkts = int(self._sysfs.tx_packets)
        rx_pkts = int(self._sysfs.rx_packets)
        tx_bytes = int(self._sysfs.tx_bytes)
        rx_bytes = int(self._sysfs.rx_bytes)

        if ((tx_pkts == -1) or (rx_pkts == -1) or (tx_bytes == -1)
                or (rx_bytes == -1)):
            self.logger.warn("Failed to read packet and byte counts from WiFi")
            return result

        # Update the link speed every 15 seconds as pulling the WifiInfo
        # structure from WifiManager is a little expensive. This isn't really
        # something that is likely to change frequently anyway

        if (iter_num % 15 == 0) or not self._speed:
            self._speed = self._wifi.get_speed()

        if self._state.is_initialized():
            result.set_sys_usage(
                WifiUsage(True, self._state.delta_pkts,
                          self._state.delta_tx_bytes,
                          self._state.delta_rx_bytes, self._state.tx_rate,
                          self._speed, self._state.pwr_state))

        self._state.update(tx_pkts, rx_pkts, tx_bytes, rx_bytes)

        uids = SystemInfo.get_uids()

        if uids is not None:
            for uid in uids:
                if uid < 0:
                    continue

                uid_state = self._uid_states.get(uid, None)

                if not uid_state:
                    uid_state = WifiState(
                        self._constants.WIFI_HIGHLOW_PKTBOUND,
                        self._constants.WIFI_LOWHIGH_PKTBOUND)
                    self._uid_states[uid] = uid_state

                if not uid_state.is_stale():
                    # Use heuristic to not poll for UIDs that haven't had much
                    # activity recently
                    continue

                # These read operations are the expensive part of polling
                with open(self.UID_TX_BYTE_MASK.format(uid)) as fp:
                    tx_bytes = int(fp.read().strip())
                with open(self.UID_RX_BYTE_MASK.format(uid)) as fp:
                    rx_bytes = int(fp.read().strip())

                if (rx_bytes == -1) or (tx_bytes == -1):
                    self.logger.warn("Failed to read UID Tx/Rx byte counts")
                elif uid_state.is_initialized():
                    # We only have info on bytes received but what we really
                    # want is the number of packets received so we will
                    # estimate it
                    delta_tx_bytes = tx_bytes - self._state.tx_bytes
                    delta_rx_bytes = rx_bytes - self._state.rx_bytes
                    tx_pkts = int(
                        round(delta_tx_bytes / self._state.avg_tx_pkt_size))
                    rx_pkts = int(
                        round(delta_rx_bytes / self._state.avg_rx_pkt_size))

                    if (delta_tx_bytes > 0) and (tx_pkts == 0):
                        tx_pkts = 1

                    if (delta_rx_bytes > 0) and (rx_pkts == 0):
                        rx_pkts = 1

                    active = ((tx_bytes != uid_state.tx_bytes)
                              or (rx_bytes != uid_state.rx_bytes))

                    uid_state.update((self._state.tx_pkts + tx_pkts),
                                     (self._state.rx_pkts + rx_pkts), tx_bytes,
                                     rx_bytes)

                    if active:
                        usage = WifiUsage(True, uid_state.delta_pkts,
                                          uid_state.delta_tx_bytes,
                                          uid_state.delta_rx_bytes,
                                          uid_state.tx_rate, self._speed,
                                          uid_state.pwr_state)
                        result.set_uid_usage(uid, usage)
                else:
                    uid_state.update(0, 0, tx_bytes, rx_bytes)

        return result