mirror of
https://github.com/mvt-project/mvt.git
synced 2024-06-25 05:48:57 +00:00
Refactor DumpsysBatteryDaily module and add related artifact
This commit is contained in:
parent
b259db30f8
commit
7e0e071c5d
78
mvt/android/artifacts/dumpsys_battery_daily.py
Normal file
78
mvt/android/artifacts/dumpsys_battery_daily.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021-2023 Claudio Guarnieri.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from typing import Union
|
||||
|
||||
from .artifact import AndroidArtifact
|
||||
|
||||
|
||||
class DumpsysBatteryDailyArtifact(AndroidArtifact):
|
||||
"""
|
||||
Parser for dumpsys dattery daily updates.
|
||||
"""
|
||||
|
||||
def serialize(self, record: dict) -> Union[dict, list]:
|
||||
return {
|
||||
"timestamp": record["from"],
|
||||
"module": self.__class__.__name__,
|
||||
"event": "battery_daily",
|
||||
"data": f"Recorded update of package {record['package_name']} "
|
||||
f"with vers {record['vers']}",
|
||||
}
|
||||
|
||||
def check_indicators(self) -> None:
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
ioc = self.indicators.check_app_id(result["package_name"])
|
||||
if ioc:
|
||||
result["matched_indicator"] = ioc
|
||||
self.detected.append(result)
|
||||
continue
|
||||
|
||||
def parse(self, output: str) -> None:
|
||||
daily = None
|
||||
daily_updates = []
|
||||
for line in output.splitlines():
|
||||
if line.startswith(" Daily from "):
|
||||
if len(daily_updates) > 0:
|
||||
self.results.extend(daily_updates)
|
||||
daily_updates = []
|
||||
|
||||
timeframe = line[13:].strip()
|
||||
date_from, date_to = timeframe.strip(":").split(" to ", 1)
|
||||
daily = {"from": date_from[0:10], "to": date_to[0:10]}
|
||||
continue
|
||||
|
||||
if not daily:
|
||||
continue
|
||||
|
||||
if not line.strip().startswith("Update "):
|
||||
continue
|
||||
|
||||
line = line.strip().replace("Update ", "")
|
||||
package_name, vers = line.split(" ", 1)
|
||||
vers_nr = vers.split("=", 1)[1]
|
||||
|
||||
already_seen = False
|
||||
for update in daily_updates:
|
||||
if package_name == update["package_name"] and vers_nr == update["vers"]:
|
||||
already_seen = True
|
||||
break
|
||||
|
||||
if not already_seen:
|
||||
daily_updates.append(
|
||||
{
|
||||
"action": "update",
|
||||
"from": daily["from"],
|
||||
"to": daily["to"],
|
||||
"package_name": package_name,
|
||||
"vers": vers_nr,
|
||||
}
|
||||
)
|
||||
|
||||
if len(daily_updates) > 0:
|
||||
self.results.extend(daily_updates)
|
|
@ -4,14 +4,14 @@
|
|||
# https://license.mvt.re/1.1/
|
||||
|
||||
import logging
|
||||
from typing import Optional, Union
|
||||
from typing import Optional
|
||||
|
||||
from mvt.android.parsers import parse_dumpsys_battery_daily
|
||||
from mvt.android.artifacts.dumpsys_battery_daily import DumpsysBatteryDailyArtifact
|
||||
|
||||
from .base import AndroidExtraction
|
||||
|
||||
|
||||
class DumpsysBatteryDaily(AndroidExtraction):
|
||||
class DumpsysBatteryDaily(DumpsysBatteryDailyArtifact, AndroidExtraction):
|
||||
"""This module extracts records from battery daily updates."""
|
||||
|
||||
def __init__(
|
||||
|
@ -32,32 +32,12 @@ class DumpsysBatteryDaily(AndroidExtraction):
|
|||
results=results,
|
||||
)
|
||||
|
||||
def serialize(self, record: dict) -> Union[dict, list]:
|
||||
return {
|
||||
"timestamp": record["from"],
|
||||
"module": self.__class__.__name__,
|
||||
"event": "battery_daily",
|
||||
"data": f"Recorded update of package {record['package_name']} "
|
||||
f"with vers {record['vers']}",
|
||||
}
|
||||
|
||||
def check_indicators(self) -> None:
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
ioc = self.indicators.check_app_id(result["package_name"])
|
||||
if ioc:
|
||||
result["matched_indicator"] = ioc
|
||||
self.detected.append(result)
|
||||
continue
|
||||
|
||||
def run(self) -> None:
|
||||
self._adb_connect()
|
||||
output = self._adb_command("dumpsys batterystats --daily")
|
||||
self._adb_disconnect()
|
||||
|
||||
self.results = parse_dumpsys_battery_daily(output)
|
||||
self.parse(output)
|
||||
|
||||
self.log.info(
|
||||
"Extracted %d records from battery daily stats", len(self.results)
|
||||
|
|
46
mvt/android/modules/androidqf/dumpsys_battery_daily.py
Normal file
46
mvt/android/modules/androidqf/dumpsys_battery_daily.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021-2023 Claudio Guarnieri.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from mvt.android.artifacts.dumpsys_battery_daily import DumpsysBatteryDailyArtifact
|
||||
|
||||
from .base import AndroidQFModule
|
||||
|
||||
|
||||
class DumpsysBatteryDaily(DumpsysBatteryDailyArtifact, AndroidQFModule):
|
||||
def __init__(
|
||||
self,
|
||||
file_path: Optional[str] = None,
|
||||
target_path: Optional[str] = None,
|
||||
results_path: Optional[str] = None,
|
||||
module_options: Optional[dict] = None,
|
||||
log: logging.Logger = logging.getLogger(__name__),
|
||||
results: Optional[list] = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
file_path=file_path,
|
||||
target_path=target_path,
|
||||
results_path=results_path,
|
||||
module_options=module_options,
|
||||
log=log,
|
||||
results=results,
|
||||
)
|
||||
|
||||
def run(self) -> None:
|
||||
dumpsys_file = self._get_files_by_pattern("*/dumpsys.txt")
|
||||
if not dumpsys_file:
|
||||
return
|
||||
|
||||
# Extract section
|
||||
data = self._get_file_content(dumpsys_file[0])
|
||||
section = self.extract_dumpsys_section(
|
||||
data.decode("utf-8", errors="replace"), "DUMP OF SERVICE batterystats:"
|
||||
)
|
||||
|
||||
# Parse it
|
||||
self.parse(section)
|
||||
self.log.info("Extracted a total of %d battery daily stats", len(self.results))
|
|
@ -4,14 +4,14 @@
|
|||
# https://license.mvt.re/1.1/
|
||||
|
||||
import logging
|
||||
from typing import Optional, Union
|
||||
from typing import Optional
|
||||
|
||||
from mvt.android.parsers import parse_dumpsys_battery_daily
|
||||
from mvt.android.artifacts.dumpsys_battery_daily import DumpsysBatteryDailyArtifact
|
||||
|
||||
from .base import BugReportModule
|
||||
|
||||
|
||||
class BatteryDaily(BugReportModule):
|
||||
class BatteryDaily(DumpsysBatteryDailyArtifact, BugReportModule):
|
||||
"""This module extracts records from battery daily updates."""
|
||||
|
||||
def __init__(
|
||||
|
@ -32,26 +32,6 @@ class BatteryDaily(BugReportModule):
|
|||
results=results,
|
||||
)
|
||||
|
||||
def serialize(self, record: dict) -> Union[dict, list]:
|
||||
return {
|
||||
"timestamp": record["from"],
|
||||
"module": self.__class__.__name__,
|
||||
"event": "battery_daily",
|
||||
"data": f"Recorded update of package {record['package_name']} "
|
||||
f"with vers {record['vers']}",
|
||||
}
|
||||
|
||||
def check_indicators(self) -> None:
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
ioc = self.indicators.check_app_id(result["package_name"])
|
||||
if ioc:
|
||||
result["matched_indicator"] = ioc
|
||||
self.detected.append(result)
|
||||
continue
|
||||
|
||||
def run(self) -> None:
|
||||
content = self._get_dumpstate_file()
|
||||
if not content:
|
||||
|
@ -61,30 +41,9 @@ class BatteryDaily(BugReportModule):
|
|||
)
|
||||
return
|
||||
|
||||
lines = []
|
||||
in_batterystats = False
|
||||
in_daily = False
|
||||
for line in content.decode(errors="ignore").splitlines():
|
||||
if line.strip() == "DUMP OF SERVICE batterystats:":
|
||||
in_batterystats = True
|
||||
continue
|
||||
|
||||
if not in_batterystats:
|
||||
continue
|
||||
|
||||
if line.strip() == "Daily stats:":
|
||||
lines.append(line)
|
||||
in_daily = True
|
||||
continue
|
||||
|
||||
if not in_daily:
|
||||
continue
|
||||
|
||||
if line.strip() == "":
|
||||
break
|
||||
|
||||
lines.append(line)
|
||||
|
||||
self.results = parse_dumpsys_battery_daily("\n".join(lines))
|
||||
dumpsys_section = self.extract_dumpsys_section(
|
||||
content.decode("utf-8", errors="replace"), "DUMP OF SERVICE batterystats:"
|
||||
)
|
||||
self.parse(dumpsys_section)
|
||||
|
||||
self.log.info("Extracted a total of %d battery daily stats", len(self.results))
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .dumpsys import (
|
||||
parse_dumpsys_battery_daily,
|
||||
parse_dumpsys_battery_history,
|
||||
parse_dumpsys_receiver_resolver_table,
|
||||
)
|
||||
|
|
|
@ -7,54 +7,6 @@ import re
|
|||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
def parse_dumpsys_battery_daily(output: str) -> list:
|
||||
results = []
|
||||
daily = None
|
||||
daily_updates = []
|
||||
for line in output.splitlines():
|
||||
if line.startswith(" Daily from "):
|
||||
if len(daily_updates) > 0:
|
||||
results.extend(daily_updates)
|
||||
daily_updates = []
|
||||
|
||||
timeframe = line[13:].strip()
|
||||
date_from, date_to = timeframe.strip(":").split(" to ", 1)
|
||||
daily = {"from": date_from[0:10], "to": date_to[0:10]}
|
||||
continue
|
||||
|
||||
if not daily:
|
||||
continue
|
||||
|
||||
if not line.strip().startswith("Update "):
|
||||
continue
|
||||
|
||||
line = line.strip().replace("Update ", "")
|
||||
package_name, vers = line.split(" ", 1)
|
||||
vers_nr = vers.split("=", 1)[1]
|
||||
|
||||
already_seen = False
|
||||
for update in daily_updates:
|
||||
if package_name == update["package_name"] and vers_nr == update["vers"]:
|
||||
already_seen = True
|
||||
break
|
||||
|
||||
if not already_seen:
|
||||
daily_updates.append(
|
||||
{
|
||||
"action": "update",
|
||||
"from": daily["from"],
|
||||
"to": daily["to"],
|
||||
"package_name": package_name,
|
||||
"vers": vers_nr,
|
||||
}
|
||||
)
|
||||
|
||||
if len(daily_updates) > 0:
|
||||
results.extend(daily_updates)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def parse_dumpsys_battery_history(output: str) -> List[Dict[str, Any]]:
|
||||
results = []
|
||||
|
||||
|
|
37
tests/android/test_artifact_dumpsys_battery_daily.py
Normal file
37
tests/android/test_artifact_dumpsys_battery_daily.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021-2023 Claudio Guarnieri.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
import logging
|
||||
|
||||
from mvt.android.artifacts.dumpsys_battery_daily import DumpsysBatteryDailyArtifact
|
||||
from mvt.common.indicators import Indicators
|
||||
|
||||
from ..utils import get_artifact
|
||||
|
||||
|
||||
class TestDumpsysBatteryDailyArtifact:
|
||||
def test_parsing(self):
|
||||
dba = DumpsysBatteryDailyArtifact()
|
||||
file = get_artifact("android_data/dumpsys_battery.txt")
|
||||
with open(file) as f:
|
||||
data = f.read()
|
||||
|
||||
assert len(dba.results) == 0
|
||||
dba.parse(data)
|
||||
assert len(dba.results) == 3
|
||||
|
||||
def test_ioc_check(self, indicator_file):
|
||||
dba = DumpsysBatteryDailyArtifact()
|
||||
file = get_artifact("android_data/dumpsys_battery.txt")
|
||||
with open(file) as f:
|
||||
data = f.read()
|
||||
dba.parse(data)
|
||||
|
||||
ind = Indicators(log=logging.getLogger())
|
||||
ind.parse_stix2(indicator_file)
|
||||
ind.ioc_collections[0]["app_ids"].append("com.facebook.system")
|
||||
dba.indicators = ind
|
||||
assert len(dba.detected) == 0
|
||||
dba.check_indicators()
|
||||
assert len(dba.detected) == 1
|
24
tests/android_androidqf/test_dumpsys_battery_daily.py
Normal file
24
tests/android_androidqf/test_dumpsys_battery_daily.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021-2023 Claudio Guarnieri.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from mvt.android.modules.androidqf.dumpsys_battery_daily import DumpsysBatteryDaily
|
||||
from mvt.common.module import run_module
|
||||
|
||||
from ..utils import get_android_androidqf, list_files
|
||||
|
||||
|
||||
class TestDumpsysBatteryDailyModule:
|
||||
def test_parsing(self):
|
||||
data_path = get_android_androidqf()
|
||||
m = DumpsysBatteryDaily(target_path=data_path)
|
||||
files = list_files(data_path)
|
||||
parent_path = Path(data_path).absolute().parent.as_posix()
|
||||
m.from_folder(parent_path, files)
|
||||
run_module(m)
|
||||
assert len(m.results) == 3
|
||||
assert len(m.timeline) == 3
|
||||
assert len(m.detected) == 0
|
|
@ -9,3 +9,52 @@ Battery History (0% used, 2720 used of 4096KB, 31 strings using 2694):
|
|||
+2d23h22m24s588ms (2) 079 +usb_data +top=u0a44:"com.sec.android.app.launcher"
|
||||
|
||||
|
||||
Daily stats:
|
||||
Current start time: 2022-08-17-01-15-45
|
||||
Next min deadline: 2022-08-18-01-00-00
|
||||
Next max deadline: 2022-08-18-03-00-00
|
||||
Current daily discharge step durations:
|
||||
#0: +3h32m16s12ms to 96 (power-save-off)
|
||||
#1: +2h44m44s14ms to 97 (screen-off, power-save-off, device-idle-on)
|
||||
#2: +2h0m41s988ms to 98 (screen-off, power-save-off, device-idle-on)
|
||||
Discharge total time: 11d 12h 30m 0s 400ms (from 3 steps)
|
||||
Discharge screen off time: 9d 21h 51m 40s 100ms (from 2 steps)
|
||||
Discharge screen off device idle time: 9d 21h 51m 40s 100ms (from 2 steps)
|
||||
Current daily charge step durations:
|
||||
#0: +5m4s541ms to 99 (screen-off, power-save-off, device-idle-off)
|
||||
#1: +3m33s300ms to 98 (screen-off, power-save-off, device-idle-off)
|
||||
Charge total time: 7h 11m 32s 0ms (from 2 steps)
|
||||
Charge screen off time: 7h 11m 32s 0ms (from 2 steps)
|
||||
Daily from 2022-08-16-15-56-39 to 2022-08-17-01-15-45:
|
||||
Charge step durations:
|
||||
#0: +5m15s53ms to 100 (screen-off, power-save-off, device-idle-off)
|
||||
#1: +5m35s358ms to 99 (screen-off, power-save-off, device-idle-off)
|
||||
#2: +3m43s598ms to 98 (screen-off, power-save-off, device-idle-off)
|
||||
#3: +3m33s400ms to 97 (screen-off, power-save-off, device-idle-off)
|
||||
#4: +2m32s364ms to 96 (screen-off, power-save-off, device-idle-off)
|
||||
#5: +3m53s485ms to 95 (screen-off, power-save-off, device-idle-off)
|
||||
#6: +3m43s317ms to 94 (screen-off, power-save-off, device-idle-off)
|
||||
#7: +3m13s27ms to 93 (screen-off, power-save-off, device-idle-off)
|
||||
#8: +1h9m49s978ms to 92 (power-save-off, device-idle-off)
|
||||
#9: +3m43s682ms to 92 (screen-off, power-save-off, device-idle-off)
|
||||
#10: +6m15s588ms to 91 (screen-off, power-save-off, device-idle-off)
|
||||
Package changes:
|
||||
Update com.facebook.services vers=385230290
|
||||
Update com.facebook.services vers=385230290
|
||||
Update com.facebook.services vers=385230290
|
||||
Update com.facebook.services vers=385230290
|
||||
Update com.facebook.services vers=385230290
|
||||
Update com.facebook.services vers=385230290
|
||||
Update com.facebook.katana vers=315814651
|
||||
Update com.facebook.katana vers=315814651
|
||||
Update com.facebook.katana vers=315814651
|
||||
Update com.facebook.katana vers=315814651
|
||||
Update com.facebook.katana vers=315814651
|
||||
Update com.facebook.katana vers=315814651
|
||||
Update com.facebook.system vers=385230279
|
||||
Update com.facebook.system vers=385230279
|
||||
Update com.facebook.system vers=385230279
|
||||
Update com.facebook.system vers=385230279
|
||||
Update com.facebook.system vers=385230279
|
||||
Update com.facebook.system vers=385230279
|
||||
|
||||
|
|
|
@ -277,3 +277,87 @@ Connection pool for /data/user/0/com.sec.android.inputmethod/databases/StickerRe
|
|||
5: [2023-07-26 16:50:25.318] [Pid:(0)]executeForLong took 2ms - succeeded, sql="PRAGMA page_count;", path=/data/user/0/com.sec.android.inputmethod/databases/StickerRecentList
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
DUMP OF SERVICE batterystats:
|
||||
Battery History (0% used, 11KB used of 4096KB, 79 strings using 9632):
|
||||
0 (19) RESET:TIME: 2023-07-27-12-34-18
|
||||
0 (2) 100 c0100024 status=discharging health=good plug=none temp=260 volt=4345 current=226 ap_temp=27 -nr_connected -wifi_ap -otg misc_event=0x0 online=1 current_event=0x0 txshare_event=0x0 charge=3000 modemRailChargemAh=0 wifiRailChargemAh=0 +running +wake_lock +screen phone_signal_strength=great brightness=bright +wifi_running +wifi +usb_data wifi_signal_strength=3 wifi_suppl=disconn +ble_scan top=1000:"com.wssyncmldm"
|
||||
0 (2) 100 c0100024 user=0:"0"
|
||||
0 (2) 100 c0100024 userfg=0:"0"
|
||||
+343ms (3) 100 80000024 -wake_lock -screen -usb_data stats=0:"get-stats"
|
||||
+1s235ms (4) 100 c0000020 +wake_lock=1000:"ActivityManager-Sleep" brightness=dark stats=0:"screen-state"
|
||||
+1s314ms (1) 100 80000020 -wake_lock
|
||||
+1s320ms (2) 100 c0000020 +wake_lock=1001:"*telephony-radio*"
|
||||
+1s321ms (1) 100 80000020 -wake_lock
|
||||
+1s321ms (2) 100 c0000020 +wake_lock=1001:"*telephony-radio*"
|
||||
+1s332ms (1) 100 80000020 -wake_lock
|
||||
+1s332ms (2) 100 c0000020 +wake_lock=1001:"*telephony-radio*"
|
||||
+1s334ms (1) 100 80000020 -wake_lock
|
||||
+1s441ms (2) 100 c0000020 +wake_lock=1000:"startDream"
|
||||
+1s751ms (1) 100 80000020 -wake_lock
|
||||
+1s809ms (2) 100 c0000020 +wake_lock=1001:"*telephony-radio*"
|
||||
+1s811ms (1) 100 80000020 -wake_lock
|
||||
+1s811ms (2) 100 c0000020 +wake_lock=1001:"*telephony-radio*"
|
||||
+1s821ms (1) 100 80000020 -wake_lock
|
||||
+1s821ms (2) 100 c0000020 +wake_lock=1001:"*telephony-radio*"
|
||||
+1s823ms (1) 100 80000020 -wake_lock -ble_scan
|
||||
+2s042ms (2) 100 c0000020 +wake_lock=u0a12:"Wakeful StateMachine: GeofencerStateMachine"
|
||||
+2s044ms (1) 100 80000020 -wake_lock
|
||||
+2s050ms (2) 100 c0000020 +wake_lock=u0a12:"NlpWakeLock"
|
||||
|
||||
Daily stats:
|
||||
Current start time: 2023-07-27-02-02-56
|
||||
Next min deadline: 2023-07-28-01-00-00
|
||||
Next max deadline: 2023-07-28-03-00-00
|
||||
Current daily discharge step durations:
|
||||
#0: +2h44m59s971ms to 98 (screen-off, power-save-off, device-idle-on)
|
||||
Discharge total time: 11d 10h 59m 57s 100ms (from 1 steps)
|
||||
Discharge screen off time: 11d 10h 59m 57s 100ms (from 1 steps)
|
||||
Discharge screen off device idle time: 11d 10h 59m 57s 100ms (from 1 steps)
|
||||
Current daily charge step durations:
|
||||
#0: +2m32s269ms to 100 (power-save-off, device-idle-off)
|
||||
Charge total time: 4h 13m 46s 900ms (from 1 steps)
|
||||
Daily from 2023-07-26-03-02-02 to 2023-07-27-02-02-56:
|
||||
Discharge step durations:
|
||||
#0: +2h21m35s4ms to 75 (screen-off, power-save-off)
|
||||
#1: +2h19m0s999ms to 76 (screen-off, power-save-off)
|
||||
#2: +1h46m26s999ms to 77 (screen-off, power-save-off)
|
||||
#3: +2h24m32s6ms to 78 (screen-off, power-save-off, device-idle-on)
|
||||
#4: +2h44m58s966ms to 79 (screen-off, power-save-off, device-idle-on)
|
||||
Discharge total time: 9d 16h 11m 19s 400ms (from 5 steps)
|
||||
Discharge screen off time: 9d 16h 11m 19s 400ms (from 5 steps)
|
||||
Discharge screen off device idle time: 10d 17h 55m 48s 600ms (from 2 steps)
|
||||
Charge step durations:
|
||||
#0: +5m45s118ms to 100 (screen-off, power-save-off, device-idle-off)
|
||||
#1: +1m0s998ms to 99 (screen-off, power-save-off, device-idle-off)
|
||||
#2: +2m1s894ms to 98 (screen-off, power-save-off, device-idle-off)
|
||||
#3: +1m0s973ms to 97 (screen-off, power-save-off, device-idle-off)
|
||||
#4: +3m33s239ms to 96 (screen-off, power-save-off, device-idle-off)
|
||||
Charge step durations:
|
||||
#0: +30s531ms to 100 (screen-off, power-save-off, device-idle-off)
|
||||
#1: +30s527ms to 99 (screen-off, power-save-off, device-idle-off)
|
||||
#2: +30s571ms to 98 (screen-off, power-save-off, device-idle-off)
|
||||
#3: +1m1s53ms to 97 (screen-off, power-save-off, device-idle-off)
|
||||
#4: +30s580ms to 96 (screen-off, power-save-off, device-idle-off)
|
||||
#5: +30s568ms to 95 (screen-off, power-save-off, device-idle-off)
|
||||
#6: +20s407ms to 94 (screen-off, power-save-off, device-idle-off)
|
||||
#7: +7m16s300ms to 93 (screen-off, power-save-off, device-idle-off)
|
||||
#8: +5m55s313ms to 92 (screen-off, power-save-off, device-idle-off)
|
||||
#9: +6m35s856ms to 91 (screen-off, power-save-off, device-idle-off)
|
||||
#10: +4m17s981ms to 90 (screen-off, power-save-off, device-idle-off)
|
||||
#11: +3m43s342ms to 89 (screen-off, power-save-off, device-idle-off)
|
||||
Charge total time: 4h 24m 18s 500ms (from 12 steps)
|
||||
Charge screen off time: 4h 24m 18s 500ms (from 12 steps)
|
||||
Package changes:
|
||||
Update com.google.android.gm vers=63983425
|
||||
Update com.google.android.gm vers=63983425
|
||||
Update com.google.android.gm vers=63983425
|
||||
Update com.google.android.gm vers=63983425
|
||||
Update org.mozilla.firefox vers=2015962857
|
||||
Update org.mozilla.firefox vers=2015962857
|
||||
Update org.mozilla.firefox vers=2015962857
|
||||
Update org.mozilla.firefox vers=2015962857
|
||||
Update com.google.android.projection.gearhead vers=99632623
|
||||
Update com.google.android.projection.gearhead vers=99632623
|
||||
Update com.google.android.projection.gearhead vers=99632623
|
||||
|
||||
|
|
|
@ -62,5 +62,5 @@ class TestHashes:
|
|||
assert hashes[1]["file_path"] == os.path.join(path, "dumpsys.txt")
|
||||
assert (
|
||||
hashes[1]["sha256"]
|
||||
== "c6be3ada77674f5bb9750d24e84b9b7ccf8db0cd4a896d9c17f9456eeab4bd0b"
|
||||
== "009f9eaa04658acdd179b463e05e1ea1fffea132e6e7ee556f0c385ee69a0811"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user