verify_reader_c4_detached.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #!/usr/bin/env python3
  2. """Verify that Compose pagination works while the legacy reader surface is laid out at 0x0."""
  3. from __future__ import annotations
  4. import argparse
  5. import json
  6. import sys
  7. import time
  8. from datetime import datetime
  9. from pathlib import Path
  10. sys.dont_write_bytecode = True
  11. from capture_reader_c3_baseline import ( # noqa: E402
  12. Adb,
  13. BaselineError,
  14. MAIN_ACTIVITY_CLASS,
  15. PACKAGE_DEFAULT,
  16. READ_ROUTE,
  17. capture,
  18. compare_pngs,
  19. connected_serial,
  20. require_unlocked,
  21. restore_lab_state,
  22. screen_size,
  23. set_compose_renderer,
  24. )
  25. DETACH_EXTRA = "readerDetachLegacySurface"
  26. FIRST_FRAME_EXTRA = "readerFirstFrameStartedAtNanos"
  27. def elapsed_realtime_nanos(adb: Adb) -> int:
  28. seconds = float(adb.run("shell", "cat", "/proc/uptime").split()[0])
  29. return int(seconds * 1_000_000_000)
  30. def main() -> int:
  31. parser = argparse.ArgumentParser(description=__doc__)
  32. parser.add_argument("--serial")
  33. parser.add_argument("--package", default=PACKAGE_DEFAULT)
  34. parser.add_argument("--settle-seconds", type=float, default=2.0)
  35. parser.add_argument("--out", type=Path)
  36. args = parser.parse_args()
  37. serial = connected_serial(args.serial)
  38. adb = Adb(serial)
  39. require_unlocked(adb)
  40. output = args.out or Path("build/reader-c4-detached") / datetime.now().strftime("%Y%m%d-%H%M%S")
  41. output.mkdir(parents=True, exist_ok=False)
  42. original: tuple[bool, bool] | None = None
  43. try:
  44. original = set_compose_renderer(adb, args.package, True)
  45. adb.run("logcat", "-c")
  46. started_at = elapsed_realtime_nanos(adb)
  47. adb.run(
  48. "shell", "am", "start", "-S", "-W",
  49. "-n", f"{args.package}/{MAIN_ACTIVITY_CLASS}",
  50. "--es", "startRoute", READ_ROUTE,
  51. "--ez", DETACH_EXTRA, "true",
  52. "--el", FIRST_FRAME_EXTRA, str(started_at),
  53. )
  54. time.sleep(args.settle_seconds)
  55. before = output / "before.png"
  56. after = output / "after.png"
  57. capture(adb, before)
  58. width, height = screen_size(adb)
  59. adb.run("shell", "input", "tap", str(int(width * 0.84)), str(int(height * 0.5)))
  60. time.sleep(args.settle_seconds)
  61. capture(adb, after)
  62. difference = compare_pngs(before, after, None)
  63. if difference["changedPixelPercent"] < 1.0:
  64. raise BaselineError("legacy surface 为 0x0 时,Compose 点击后画面未发生有效变化")
  65. logs = adb.run("logcat", "-d", "-s", "ReaderDetachedLegacy:I", "ReaderFirstFrame:I", "*:S")
  66. if "legacySurface=0x0" not in logs:
  67. raise BaselineError("未观察到 committed detach 分支日志")
  68. if "renderer=compose" not in logs:
  69. raise BaselineError("未观察到 Compose 首个非空正文帧")
  70. result = {"serial": serial, "difference": difference, "logs": logs.strip().splitlines()}
  71. (output / "result.json").write_text(
  72. json.dumps(result, ensure_ascii=False, indent=2),
  73. encoding="utf-8",
  74. )
  75. print(json.dumps({"output": str(output), **result}, ensure_ascii=False, indent=2))
  76. return 0
  77. finally:
  78. restore_lab_state(adb, args.package, original)
  79. if __name__ == "__main__":
  80. raise SystemExit(main())