This file is indexed.

/usr/lib/plainbox-providers-1/checkbox/bin/battery_test is in plainbox-provider-checkbox 0.3-2.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env python3

import os
import time
import re
import subprocess
import sys
import argparse
from gi.repository import Gio


class Battery():

    def __init__(self, data):
        lines = data.split("\n")
        for line in lines:
            if line.find("state:") != -1:
                self._state = line.split(':')[1].strip()
            elif line.find("energy:") != -1:
                self._energy, self._energy_units = self._get_capacity(line)
            elif line.find("energy-full:") != -1:
                self._energy_full, self._energy_full_units =\
                    self._get_capacity(line)
            elif line.find("energy-full-design:") != -1:
                self._energy_full_design, self._energy_full_design_units =\
                    self._get_capacity(line)

    def _get_capacity(self, line):
        """
        Given a line of input that represents a battery capacity (energy)
        value, return a tuple of (value, units).  Value is returned as a
        float.
        """
        capacity = line.split(':')[1].strip()
        values = capacity.split()
        return (float(values[0]), values[1])

    def __str__(self):
        ret = "-----------------------------------------\n"
        ret += "State: %s\n" % self._state
        ret += "Energy: %s %s\n" % (self._energy, self._energy_units)
        ret += "Energy Full: %s %s\n" % (self._energy_full,
                                         self._energy_full_units)
        ret += "Energy Full-Design: %s %s\n" % (self._energy_full_design,
                                                self._energy_full_design_units)
        return ret


def find_battery():
    batinfo = subprocess.Popen('upower -d',
                               stdout=subprocess.PIPE, shell=True,
                               universal_newlines=True)
    if not batinfo:
        return None
    else:
        out, err = batinfo.communicate()
        if out:
            device_regex = re.compile("Device: (.*battery_.*)")
            batteries = device_regex.findall(out)
            if len(batteries) == 0:
                return None
            elif len(batteries) > 1:
                print("Warning: This system has more than 1 battery, only the"
                      "first battery will be measured")
            return batteries[0]
        else:
            return None


def get_battery_state():
    battery_name = find_battery()
    if battery_name is None:
        return None

    batinfo = subprocess.Popen('upower -i %s' % battery_name,
                               stdout=subprocess.PIPE, shell=True,
                               universal_newlines=True)
    if not batinfo:
        return None
    else:
        out, err = batinfo.communicate()
        if out:
            return Battery(out)
        else:
            return None


def validate_battery_info(battery):
    if battery is None:
        print ("Error obtaining battery info")
        return False
    if battery._state != "discharging":
        print ("Error: battery is not discharging, test will not be valid")
        return False
    return True


def battery_life(before, after, time):
    capacity_difference = before._energy - after._energy
    print("Battery drained by %f %s" % (capacity_difference,
                                        before._energy_units))
    if capacity_difference == 0:
        print("Battery capacity did not change, unable to determine remaining"
              " time", file=sys.stderr)
        return 1
    drain_per_second = capacity_difference / time
    print("Battery drained %f %s per second" % (drain_per_second,
                                                before._energy_units))

    # the battery at it's max design capacity (when it was brand new)
    design_life_minutes = round(
        ((before._energy_full_design / drain_per_second) / 60), 2)
    print("Battery Life with full battery at design capacity (when new): %.2f"
          "minutes" % (design_life_minutes))

    # the battery at it's current max capacity
    current_full_life_minutes = round(
        ((before._energy_full / drain_per_second) / 60), 2)
    print("Battery Life with a full battery at current capacity: %.2f minutes"
          % (current_full_life_minutes))

    # the battery at it's current capacity
    current_life_minutes = round(
        ((before._energy / drain_per_second) / 60), 2)
    print("Battery Life with at current battery capacity: %.2f minutes" %
          (current_life_minutes))
    return 0


def main():
    parser = argparse.ArgumentParser(
        description="""Determine battery drain and battery life by running
                       the specified action.  Battery life is shown for:
                       current capacity, capacity when battery is full,
                       and capacity when battery is full and was brand new
                       (design capacity)""")
    parser.add_argument('-i', '--idle', help="Run the test while system is"
                        " idling", action='store_true')
    parser.add_argument('-s3', '--sleep', help="Run the test while system"
                        " is suspended", action='store_true')
    parser.add_argument('-t', '--time',
                        help="Specify the allotted time in seconds to run",
                        type=int, required=True)
    parser.add_argument('-m', '--movie',
                        help="Run the test while playing the file MOVIE")
    args = parser.parse_args()

    test_time = args.time
    battery_before = get_battery_state()
    if not validate_battery_info(battery_before):
        return 1
    print(battery_before)

    if args.idle:
        time.sleep(test_time)
    elif args.movie:
        totem_settings = Gio.Settings.new("org.gnome.totem")
        totem_settings.set_boolean("repeat", True)
        a = subprocess.Popen(['totem', '--fullscreen', args.movie])
        time.sleep(test_time)
        a.kill()
        totem_settings = Gio.Settings.new("org.gnome.totem")
        totem_settings.set_boolean("repeat", False)
    elif args.sleep:
        subprocess.call(['fwts', 's3', '--s3-sleep-delay=' + str(test_time)])

    battery_after = get_battery_state()
    if not validate_battery_info(battery_after):
        return 1
    print(battery_after)

    return(battery_life(battery_before, battery_after, test_time))

if __name__ == "__main__":
    sys.exit(main())