Commit graph

3868 commits

Author SHA1 Message Date
Treehugger Robot
a45e51339d Merge "Add dm-thin support" into main 2024-04-03 21:46:00 +00:00
Jooyung Han
2f814176ea Add dm-thin support
thin-pool and thin targets are supported via DmTargetThinPool and
DmTargetThin. DM_TARGET_MSG is also added via a new method
SendMessage() because it's used to create a thin volumn.

dmctl is extended to support thin-pool and thin targets.

TODO: thin-pool target constructor can accept feature arguments.

Bug: 327081431
Test: atest libdm_test (CF with dm-thin enabled kernel)
Change-Id: I4c51c668bfe1489b959f6d03c205a5e2e63d9a1d
2024-04-03 10:47:47 +09:00
Treehugger Robot
2dab9f2968 Merge "snapshotctl: Build few commands only for userdebug/eng builds" into main 2024-04-02 17:39:16 +00:00
Akilesh Kailash
a2aa83c5a5 libsnapshot: don't kill the daemon for legacy vab snapshots
If partitions are mounted off the daemon, there is no need
to kill if the tests are being run for legacy vab snapshots.

This also removes vabc_legacy_test as it is no longer required.

Bug: 331053511
Test: vab_legacy_test, vts_libsnapshot_test on Pixel - No flake observed
with 10 iterations
Change-Id: Ie8b29fef77948d23d920c19d816376290cf2fed9
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-03-27 22:49:04 +00:00
Akilesh Kailash
b0cf1d2370 libsnapshot: Propagate legacy_snapuserd status during WriteUpdateState
Bug: 304829384
Test: OTA on Pixel
Change-Id: I841612c111148523d13166051512314d6fa1986f
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-03-26 19:59:02 -07:00
Daniel Zheng
98df25ba2e Merge "libsnapshot: Cache Ops correctly" into main 2024-03-26 21:55:13 +00:00
Daniel Zheng
abd3552713 Merge "libsnapshot: remove temporary solution" into main 2024-03-26 21:55:13 +00:00
Akilesh Kailash
c375878b8e snapuserd: Use snapshots during install
If on Androd 12, continue to use snapshots

Bug: 304829384
Test: OTA on Pixel
Change-Id: I94890c308e7f297b695ddbd71659ebb1cf4d278c
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-03-26 16:36:01 +00:00
Akilesh Kailash
35d5c94bb0 libsnapshot: Enable snapshots during OTA install for S vendor
ro.virtual_ab.userspace.snapshots.enabled is a vendor property which isn't present in Android S. Hence, during OTA install with S vendor, userspace_snapshots is disabled.

However, both update_engine and snapuserd are already on the system partition during install. Hence, forcefully enable userspace_snapshots if this is a path of legacy dm-snapshots with Vendor on Android S.


Bug: 331156940
Test: OTA tests on treehugger, pixel OTA
Change-Id: I3d1c03493d83e670e37df088d4b676c4aa1dc720
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-03-25 21:10:05 +00:00
Akilesh Kailash
da9db4f396 Merge changes Id9263be8,Idd9a60b0 into main
* changes:
  snapuserd: Remove legacy dm-snapshot based snapshot and snapshot-merge
  libsnapshot: Prepare removal of legacy snapshot
2024-03-25 07:50:30 +00:00
Daniel Zheng
5e8e488c13 libsnapshot: Cache Ops correctly
Change the meaning of batch_size_. Previously, a batch size of 200 meant
200 compressed data ops. With variable block size, each compressed data
op can be up to 256k uncompressed size -> batch size meaning should be
changed to 200 blocks of block size.

With this being said, the default batch size can be increased to 4mb to
better accomodate variable block size

The way we calculate the number of blocks to compress at once also
needs to be changed. Since there's no way of determining the comperssed
data size ahead of time, allow overwriting the cache by batch_size_ and
then flushing the cache as needed

Bug: 322279333
Test: Ota on pixel and measuring system image cow
Change-Id: Ie8e08d109dc5c3b4f5f36a740bbbcd37362a7ab3
2024-03-22 14:47:45 -07:00
Daniel Zheng
d7efbea407 cow_api_test: big replace op
With the modified cache system we might be processing big replace ops at
once. Our old tests didn't catch a case where a big replace op was
chunked into seperate batch writes.

Test: cow_api_test
Change-Id: I3bc80a2f9ed3e4c73dd9f74d9affaba79d49e4d2
2024-03-22 14:47:45 -07:00
Daniel Zheng
c60d2fc566 libsnapshot: chunk iov writes
Currently if our iov that we are trying to write is greater than 1024
our write will fail with error "INVALID ARGUMENT". This is because
pwritev() system call takes a max input size of IOV_MAX (which is device
dependant).

With our increased cache size of 1mb or maybe even more (or if user
configures batch size to be large), our write size could be greater than
IOV_MAX, and will fail with an unhelpful error. We should chunk these
writes to ensure they succeed.

Bug: 322279333
Test: cow_api_test + manual testing with large iov write sizes
Change-Id: Ia1fb53cbfc743cfcdfc7256ff9df075ad0c2dd38
2024-03-21 10:52:37 -07:00
Treehugger Robot
a8c6a92f43 Merge "liblp_builder_fuzzer: Bug Fix" into main 2024-03-21 04:29:17 +00:00
Akilesh Kailash
92b7d837b9 snapuserd_test: check writer != nullptr
Cow Writer used to fail with ENOSPC during initialization.

Try temporaryFile creation with path set to current working directory.

Bug: 328879200
Test: th, snapuserd_test
Change-Id: I7b3833967952c74142f1d5a35cb8d94dd6d894fc
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-03-21 00:21:11 +00:00
Akilesh Kailash
10233e2fc4 snapuserd: Remove legacy dm-snapshot based snapshot and snapshot-merge
Clean up all the legacy dm-snapshot based approach.

This will continue to maintain backward compatibility with vendor
partition on Android S.

Bug: 304829384
Test: OTA on Pixel
th - OTA from Android S to TOT with vendor on S
Change-Id: Id9263be881dd1a06923cd0ace007f1c027e6969d
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-03-20 11:10:49 -07:00
Akilesh Kailash
25eabc44f5 libsnapshot: Prepare removal of legacy snapshot
During OTA install, when vendor partition is on Android S, add a new flag in SnapshotUpdateStatus file to indicate that we need to support dm-snapshot based snapshot process. This will be used only during post OTA reboot.

The primary change here is the OTA install path. Earlier, dm-snapshot based approach was used; with this change, since both "snapuserd" and "update-engine" resides on system partition, OTA installation will use the userspace snapshot approach.

To maintain backward compatibility, the new flag "legacy_snapuserd" is used only after OTA reboot. This flag will make sure that update-engine will take the dm-snapshot based approach post reboot and for the entire duration of snapshot-merge.

Additionally, during first-stage init if the vendor is on Android S, then "snapuserd" binary will continue to work based off dm-snapshot as none of this change will impact the mount process.

Bug: 304829384
Test: OTA on Pixel
th - OTA from Android S to TOT with vendor on S
Change-Id: Idd9a60b09417cee141b2810e2d4b35e91c845a5c
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-03-20 11:08:18 -07:00
Harsh Abichandani
553c9d4fb6 liblp_builder_fuzzer: Bug Fix
Updated FuzzedDataProvider value ranges to avoid Abort due to division by zero.

exec/s: 14786
Test: ./liblp_builder_fuzzer clusterfuzz-testcase-minimized-liblp_builder_fuzzer-5371251289292800
Bug: 328948968

Change-Id: I2568bd104b5fb09744baf42ffca6aabd24797b12
2024-03-19 13:36:07 +05:30
Daniel Zheng
8e6ab87328 libsnapshot: reserve 16x space for ops
We have updated logic for v3 cow we should allow non-data ops to be
cached at 16x the amount of data ops. Changing the reserve size to match
this.

Test: th
Change-Id: I825ffef4e1a2ce4eb5c105d266bf95cb3d776ed9
2024-03-19 00:34:15 -07:00
Treehugger Robot
0b671f4432 Merge "dmctl: add report of IMA" into main 2024-03-18 16:59:31 +00:00
Jaegeuk Kim
9459f7c09c dmctl: add report of IMA
This adds an option "ima" in dmctl.

$ dmctl ima product-verity
Targets in the device-mapper table for product-verity:
0-7463768: verity, target_name=verity,target_version=1.9.0,hash_failed=V,verity_version=1,data_device_name=254:4,hash_device_name=254:4,verity_algorithm=sha256,root_digest=d7af9fcb04d184219ba5477b97bb2bbc89fd23a46e03d1dea31d674cc4934769,salt=19d4f2345adfc8b7cc22a3c2f21dd413e5020fc7920a08a33f46f3c61492dfcc,ignore_zero_blocks=y,check_at_most_once=n,verity_mode=restart_on_corruption;

Change-Id: I057970b6c786b3f9a394b4919f5f5115b27cbc08
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
2024-03-15 16:34:20 -07:00
Daniel Zheng
da960a1341 libsnapshot: remove temporary solution
Remove temporary estimation solution (using 4k to overestimate the cow).
With the updated estimation logic, we should be able to accurately
estimate the cow size with variable block sized compression

Bug: 322279333
Test: th
Change-Id: I199970048605a8d21d3791614ad88ca61662e1a3
2024-03-13 22:28:43 -07:00
Jiakai Zhang
6480d875b5 Make snapshotctl also log to logd.
Since http://r.android.com/2994274, snapshotctl can be run by init.
Therefore, we need it to log to logd for better debuggability.

Bug: 311377497
Test: adb shell setprop sys.snapshotctl.map requested
Test: adb shell setprop sys.snapshotctl.unmap requested
Change-Id: I287ecf77d45fb9e6c44bea36e14d2624029afea5
2024-03-08 18:56:13 +00:00
Kelvin Zhang
eed1c42087 Merge "Add annotations to VTS tests" into main 2024-03-01 02:35:40 +00:00
Kelvin Zhang
98522c0e2d Add annotations to VTS tests
This helps reviewers understand which VTS requirement these test are
covering

Bug: 302208814
Test: th
Change-Id: I52712d9888b73fc7a9f8eeeb035a3303618efd69
2024-02-29 14:30:35 -08:00
Akilesh Kailash
b9f2361dd9 snapshotctl: Build few commands only for userdebug/eng builds
Bug: 319309466
Test: Build on -user and -userdebug targets
Change-Id: I2a668193972495769ecedbb687f561ed7345ffbc
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-02-29 13:58:46 -08:00
Treehugger Robot
b6fc19c308 Merge "adb-remount-test: Adb shell command could return 0 or 255 if device is disconnected" into main 2024-02-29 16:59:14 +00:00
Yi-Yo Chiang
2f298bcb21 adb-remount-test: Adb shell command could return 0 or 255 if device is
disconnected

Background: aosp/I25f740bd222263fcb3c501def38977db6af1e0d9

Bug: 327552188
Test: abtd
Change-Id: Ida33bfa00887e8ac358e057fc37fd45095ccc26b
2024-02-29 19:45:14 +08:00
Akilesh Kailash
3aef00da3d Merge "Reapply "snapshotctl: Add apply-update option"" into main 2024-02-29 06:27:11 +00:00
Treehugger Robot
8fefa5a96b Merge "Support for striped in libdm" into main 2024-02-28 23:16:32 +00:00
Akilesh Kailash
cac1cf3ae9 Reapply "snapshotctl: Add apply-update option"
This reverts commit 1af7260931.

Fix: Allow BootControlClient.h to be used in -user builds

Bug: 319309466
Test: Build on -user branch
Change-Id: I93e95e35b29a98816b2f33fe9fa6859655934cd5
2024-02-28 11:29:10 -08:00
Raphaël Hérouart
1af7260931 Revert "snapshotctl: Add apply-update option"
This reverts commit 77337c2975.

Reason for revert: b/327325747

Change-Id: I6796717774d28a7c306e19dd448c3c830f3fd550
2024-02-28 10:12:05 +00:00
Akilesh Kailash
77337c2975 snapshotctl: Add apply-update option
$snapshotctl apply-update <directory containing snapshot patches>

This command is equivalent to applying incremental-ota but
bypasses all of the update-engine subsystem. Snapshot-patches
which are created on the host will be used directly and
will be written to the COW block devices.

No change to any of the libsnapshot or the I/O path logic.

Once the snapshot patches are applied, device is ready
to reboot as if an OTA update is applied.

Once the device reboots, snapshot merge will be initiated
as usual.

This will help test the changes to libsnapshot + init + snapuserd
extremely quick.

Incremental flashing becomes quite simple in the CI workflow.

Here are numbers tested on live builds where the actual builds/testing
is done on CI.

Patch-Create+Apply = Create the snapshot patches between two
builds and apply them to the device

Branch(main)     Patch-Creation+Apply Merge        Snapshot-size
=================================================================
Build-1 -> Build-2  14 seconds        40 seconds   160MB

Build-2 -> Build-3  21 seconds        26 seconds   331MB

Build-3 -> Build-4  30 seconds        45 seconds   375MB

Build-X -> Build-X  3 seconds	       4 seconds   8MB

Bug: 319309466
Test: On Pixel 6, incremental builds

Change-Id: I271b2cb5df4abde91571ec70ce06f926a1d01694
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-02-27 14:21:14 -08:00
Akilesh Kailash
69d574c612 libsnapshot: Fetch device size from header
Now that V3 is enabled, relax the header version check.
For V3, header op_count_max contains the information of the device size.

Bug: 299011882
Test: snapshotctl map-snapshots on Pixel with V3 format

Change-Id: Ia1cb20b24857136a742e20408ee95e56e98b256a
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-02-23 22:26:42 +00:00
Daniel Zheng
bee3f962fc libsnapshot: stride compression
Alternate dispatching blocks between threads rather than splitting the
data beforehand and then sending to threads in order to ensure that
single threading + multithreading chunks data at the same locations.
Without this change, the resulting op count + data section of the cow
will differ between --enable-threading && --disable-threading at
runtime, which is a result we don't want

Test: th
Change-Id: I3ed8add0552745a281fce2aa7f1d1d32eb547e63
2024-02-22 21:38:47 -08:00
Ed Tsai
43de4ef22d Support for striped in libdm
Add dm stripe in dmctl framework to support stripe on two block devices.

Bug: 321628121
Change-Id: I2f326f19f7ccff1ee03598743022fb702b3e8d6a
Signed-off-by: Ed Tsai <ed.tsai@mediatek.com>
2024-02-23 08:11:30 +08:00
Daniel Zheng
25de579429 libsnapshot: log compression algorithm
Log the compression algorithm and compression factor used during OTA for easier debugging

Test: th
Change-Id: Ic50989d7e233983d6299163fc647eb739a0b7cb2
2024-02-21 10:14:06 -08:00
Daniel Zheng
4f5a9950b2 Merge "libsnapshot: update opcountcheck" into main 2024-02-21 17:22:40 +00:00
Daniel Zheng
dccf1b6e39 libsnapshot: update opcountcheck
Since variable block compresses blocks and there is no longer a 1:1
mapping between ops to blocks, we need to update this check in
EmitBlocks to the actual number of compressed blocks written.

Since single threaded + multi threaded + no compression invoke different
code paths. Ensure that that blocks written are still equivalent to
blocks.size(). Adding two test cases to cover these situations.

Test: th
Change-Id: If81eccf74333292a114268862dde0fe49681ef35
2024-02-21 09:22:07 -08:00
Akilesh Kailash
e5bc36900e create_snapshot: Enable v3 writer + variable block size
1: Move to v3 COW writer

2: Enable variable block size. Default compression set to lz4
with compression factor 64KiB

3: Prepare merge sequence so that device can initiate the merge

4: Verify the merge order

Bug: 319309466

Test: On Pixel 6

This was tested on live builds where the actual builds/testing
is done on CI.

Patch-Create+Apply = Create the snapshot patches between two
builds and apply them to the device

Branch(main)            Patch-Creation+Apply  Snapshot-size
=============================================================
Build-1 -> Build-2      14 seconds            160MB

Build-2 -> Build-3      21 seconds            331MB

Build-3 -> Build-4      30 seconds            375MB

Build X -> Build X      3 seconds             8MB

Change-Id: I96437032de029d89de62ba11fe37d9287b0a4071
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-02-11 23:19:22 -08:00
Ryan Prichard
abb472c238 libsnapshot: replace non-character basic_string[_view]<T>
In newer versions of libc++, std::char_traits<T> is no longer defined
for non-character types, and a result, std::basic_string<T> and
std::basic_string_view<T> are also no longer defined for non-character
types. See
https://discourse.llvm.org/t/deprecating-std-string-t-for-non-character-t/66779.

Replace them with std::vector<T> and std::span<const T>.

Bug: 175635923
Test: m MODULES-IN-system-core-fs_mgr
Test: /data/nativetest64/cow_api_test/cow_api_test
Change-Id: Ife2e87833ced43ff24e5765998cb6993e4f9b4c0
2024-02-08 23:20:10 -08:00
Treehugger Robot
eadf6b4bda Merge "remount: Auto remount option (-R) also tries to gain root" into main 2024-02-05 23:47:54 +00:00
Akilesh Kailash
3ea911bc06 snapuserd: Add I/O path support for variable block size
The flow of I/O path is as follows:

1: When there is a I/O request for a given sector, we first
check the in-memory COW operation mapping for that sector.

2: If the mapping of sector to COW operation is found, then the
existing I/O path will work seamlessly. Even if the COW operation
encodes multiple blocks, we will discard the remaining data.

3: If the mapping of sector to COW operation is not found:
    a: Find the previous COW operation as the vector has sorted sectors.

    b: If the previous COW operation is a REPLACE op:
        i: Check if the current sector is encoded in the previous COW
	operations compressed block.

	ii: If the sector falls within the range of compressed blocks,
	retrieve the block offset.

	iii: De-compress the COW operation based on the compression
	factor.

	iv: memcpy the data based on the block offset.

	v: cache the COW operation pointer as subsequent I/O requests
	are sequential and can just be a memcpy at the correct offset.
    c: If the previous COW operation is not a REPLACE op or if the
       requested sector does not fall within the compression factor
       of the previous COW operation, then fallback and read the data
       from base device.

Snapshot-merge:

During merge of REPLACE ops, read the entire op in one shot, de-compress
multiple blocks and write all the blocks in one shot.

Performance:

go/variable-block-vabc-perf covers detail performance runs
on Pixel 6 for full and incremental OTA.

Bug: 319309466

Test: snapuserd_test covers all the I/O path with various block sizes.
About 252 cases with all combinations and tunables.

[==========] 252 tests from 4 test suites ran. (702565 ms total)
[  PASSED  ] 252 tests.

On Pixel 6:

=======================================
COW Writer V3:

for i in full, incremental OTA
   for j in 4k, 16k, 32k, 64k, 128, 256k
      for k in lz4, zstd, gz
	 install OTA, reboot, verify merge
=======================================
COW Writer V2:

for i in full, incremental OTA
  for j in 4k
    for k in lz4, zstd, gz
      install OTA, reboot, verity merge

=====================================

Change-Id: I4c3b5c3efa0d09677568b4396cc53db0e74e7c99
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-01-31 13:28:45 -08:00
Akilesh Kailash
59fa486703 libsnapshot_cow: Support multi-block compression
This patch supports compression for bigger block size.

3 bits [57-59] in the COW Operation "source_info_" field is used to store
the compression factor. Supported compression factors are power of 2
viz: 4k, 8k, 16k, 32k, 64k, 128k, 256k.

Only REPLACE operations will have the bigger block size support for now.
This can be extended to other operations later.

The write path in EmitBlocks() has the core logic wherein consecutive
sequence of REPLACE ops are compressed based on the compression factor
settings. Thus, for a 64k compression factor, there will be just one
COW operation which encodes all the 16 operation and the entire 64k
block is compressed in one shot.

NOTE: There is no read I/O path support in this patch. Subsequent patch
will have the read support.

Performance data (with read I/O path support in subsequent patch):

go/variable-block-vabc-perf covers detail performance runs
on Pixel 6 for full and incremental OTA.

TL;DR:

Performance of a full OTA (All numbers are compared against 4k block
size)
=======================================
Snapshot-size:

~10-11% decrease in snapshot-size (disk-space) for zstd with 256k block
size.

~8% decrease in snapshot-size (disk-space) for lz4

Install time:

~13% decrease in OTA install time for zstd with 256k block size.

Snapshot-merge:

~50% decrease in snapshot-merge time with 256k block size for zstd

Post OTA boot-time:

~10.5 decrease in boot time for 64k block size for zstd

In-memory footprint for COW operations:

~80% decrease in memory footprint for 256k block size. (58MB -> 9.2MB)

============================================

For more improvements, further tuning of zstd/lz4 is
required primariy the compression levels, zstd compression window,
performance of gz with compression levels.

Bug: 319309466

Test: cow_api test covering all the supported block sizes for v3 writer.

On Pixel 6:

=======================================
COW Writer V3:

for OTA in full, incremental OTA
   for block_size in 4k, 16k, 32k, 64k, 128k, 256k
       for compression_algo in lz4, zstd, gz, none
          install OTA, reboot, verify merge
=======================================
COW Writer V2:

for OTA in full, incremental OTA
   for block_size in 4k
      for compression_algo in lz4, zstd, gz, none
          install OTA, reboot, verity merge

=====================================
Change-Id: I96201f1609582aa9d44d8085852e284b0c4a426d
Signed-off-by: Akilesh Kailash <akailash@google.com>
2024-01-31 12:52:31 -08:00
Daniel Zheng
bcce91603b libsnapshot: set header max_compression
Intermediate CL needed before variable block size can land. Since v3 is
enabled on cuttlefish, the base build needs to write the
compression_factor in order for reader to properly parse. Otherwise
we'll fail OTA test

Test: th
Change-Id: Ia353aae8e668858851073f09308909ae70d7854e
2024-01-31 17:35:00 +00:00
Daniel Zheng
6ca4d66a05 libsnapshot: update type
num_compress_threads should be unsigned integer as it can never be
negative.

Test: th
Change-Id: Ic0456ac717483300fa9cbd55eba5cdd0156207a7
2024-01-30 09:25:23 -08:00
Daniel Zheng
2aed5a5e4c libsnapshot: op_count_max default to max blocks
In the case that op_count_max is read in as zero, we should use the
upper bound of max blocks as the estimation. One case in which this
error can happen is if a v2 cow estimator is used, we should still be
able to run an OTA if we upper bound our ops buffer size estimation.

Test: th
Change-Id: I97ca66368d6631bf43c8911ed66f99c9e8096e2d
2024-01-30 09:25:15 -08:00
Daniel Zheng
2c82c81f12 libsnapshot: use compression_factor in ota
Parse manifest compression_factor and set CowOptions appropriately. This
allows v3 writer to use compression factor in OTA. Updating some
comments about supported compression algorithms

Test: th
Change-Id: I88f254087e536d9e5925064f85317f0acce280ee
2024-01-30 09:25:02 -08:00
Daniel Zheng
d84857fcfc libsnapshot: remove op count check
With variable block size compression being added, the number of ops
written cannot be calculated directly as easily since one op can cover
the data for multiple ops previously. We can get rid of this check for
XOR and Raw blocks as
within WriteOperation() we already make a check to see if we are
exceeding op_count_max limit.

We still need to keep this check for EmitZeroBlocks and EmitCopyBlocks
since the number of operations is determined ahead of time in those
function calls. Without this check in place, the ops will be added to
cached ops and return true when ops cannot be written.
with this change, v3 cow ota now works on cuttlefish with support for
variable block size compression.

Test: th
Change-Id: Ia55f152f5deb67a9022d0feff112345e72741dd3
2024-01-29 14:04:18 -08:00
Daniel Zheng
903f8e07ff libsnapshot: v3 structural changes
Changes to structure of v3 header + operation needed for variable block
size. Seperating this CL from the variable block size one so we can get
v3 enabled on cuttlefish

the op count type changes are so that op count matches the type of
max_blocks. Max_blocks is used when op buffer size is not set -> we
default to upper bound of one operation per block in the partition.

Test: th
Bug: 307452468
Change-Id: I1a2581763a4fd6be5d5795f7e4781023e9984256
2024-01-29 14:04:17 -08:00