Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #pragma once |
| 18 | |
Yurii Zubrytskyi | 3fde572 | 2021-02-19 00:08:36 -0800 | [diff] [blame] | 19 | #include <android-base/function_ref.h> |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 20 | #include <android-base/unique_fd.h> |
| 21 | #include <android/content/pm/DataLoaderParamsParcel.h> |
| 22 | #include <android/content/pm/FileSystemControlParcel.h> |
Songchun Fan | 68645c4 | 2020-02-27 15:57:35 -0800 | [diff] [blame] | 23 | #include <android/content/pm/IDataLoader.h> |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 24 | #include <android/content/pm/IDataLoaderStatusListener.h> |
Alex Buynytskyy | aa8e95e | 2020-12-14 21:50:04 -0800 | [diff] [blame] | 25 | #include <android/os/incremental/PerUidReadTimeouts.h> |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 26 | #include <binder/IAppOpsCallback.h> |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 27 | #include <binder/IServiceManager.h> |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 28 | #include <binder/Status.h> |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 29 | #include <incfs.h> |
Yurii Zubrytskyi | 8632140 | 2020-04-09 19:22:30 -0700 | [diff] [blame] | 30 | #include <jni.h> |
Alex Buynytskyy | cca2c11 | 2020-05-05 12:48:41 -0700 | [diff] [blame] | 31 | #include <utils/Looper.h> |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 32 | |
Yurii Zubrytskyi | 4a25dfb | 2020-01-10 11:53:24 -0800 | [diff] [blame] | 33 | #include <memory> |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 34 | #include <span> |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 35 | #include <string> |
| 36 | #include <string_view> |
| 37 | |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 38 | namespace android::incremental { |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 39 | |
Alex Buynytskyy | 46d3ddb | 2020-05-29 12:05:05 -0700 | [diff] [blame] | 40 | using Clock = std::chrono::steady_clock; |
| 41 | using TimePoint = std::chrono::time_point<Clock>; |
| 42 | using Milliseconds = std::chrono::milliseconds; |
| 43 | using Job = std::function<void()>; |
| 44 | |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 45 | // --- Wrapper interfaces --- |
| 46 | |
Yurii Zubrytskyi | 4a25dfb | 2020-01-10 11:53:24 -0800 | [diff] [blame] | 47 | using MountId = int32_t; |
| 48 | |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 49 | class VoldServiceWrapper { |
| 50 | public: |
Yurii Zubrytskyi | 4a25dfb | 2020-01-10 11:53:24 -0800 | [diff] [blame] | 51 | virtual ~VoldServiceWrapper() = default; |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 52 | virtual binder::Status mountIncFs( |
| 53 | const std::string& backingPath, const std::string& targetDir, int32_t flags, |
Songchun Fan | f949c37 | 2021-04-27 11:26:25 -0700 | [diff] [blame] | 54 | const std::string& sysfsName, |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 55 | os::incremental::IncrementalFileSystemControlParcel* result) const = 0; |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 56 | virtual binder::Status unmountIncFs(const std::string& dir) const = 0; |
| 57 | virtual binder::Status bindMount(const std::string& sourceDir, |
| 58 | const std::string& targetDir) const = 0; |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 59 | virtual binder::Status setIncFsMountOptions( |
Alex Buynytskyy | c144cc4 | 2021-03-31 22:19:42 -0700 | [diff] [blame] | 60 | const os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs, |
Songchun Fan | f6c65bb | 2021-05-10 16:17:30 -0700 | [diff] [blame^] | 61 | bool enableReadTimeouts, const std::string& sysfsName) const = 0; |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 62 | }; |
| 63 | |
Songchun Fan | 68645c4 | 2020-02-27 15:57:35 -0800 | [diff] [blame] | 64 | class DataLoaderManagerWrapper { |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 65 | public: |
Songchun Fan | 68645c4 | 2020-02-27 15:57:35 -0800 | [diff] [blame] | 66 | virtual ~DataLoaderManagerWrapper() = default; |
Alex Buynytskyy | ea1390f | 2020-04-22 16:08:50 -0700 | [diff] [blame] | 67 | virtual binder::Status bindToDataLoader( |
Alex Buynytskyy | b19ee3e | 2021-02-06 20:31:43 -0800 | [diff] [blame] | 68 | MountId mountId, const content::pm::DataLoaderParamsParcel& params, int bindDelayMs, |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 69 | const sp<content::pm::IDataLoaderStatusListener>& listener, bool* result) const = 0; |
| 70 | virtual binder::Status getDataLoader(MountId mountId, |
| 71 | sp<content::pm::IDataLoader>* result) const = 0; |
Alex Buynytskyy | ea1390f | 2020-04-22 16:08:50 -0700 | [diff] [blame] | 72 | virtual binder::Status unbindFromDataLoader(MountId mountId) const = 0; |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 73 | }; |
| 74 | |
| 75 | class IncFsWrapper { |
| 76 | public: |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 77 | using Control = incfs::Control; |
| 78 | using FileId = incfs::FileId; |
| 79 | using ErrorCode = incfs::ErrorCode; |
Alex Buynytskyy | bc0a7e6 | 2020-08-25 12:45:22 -0700 | [diff] [blame] | 80 | using UniqueFd = incfs::UniqueFd; |
Alex Buynytskyy | 8ef61ae | 2020-05-08 16:18:52 -0700 | [diff] [blame] | 81 | using WaitResult = incfs::WaitResult; |
Yurii Zubrytskyi | a5946f7 | 2021-02-17 14:24:14 -0800 | [diff] [blame] | 82 | using Features = incfs::Features; |
Songchun Fan | f949c37 | 2021-04-27 11:26:25 -0700 | [diff] [blame] | 83 | using Metrics = incfs::Metrics; |
Songchun Fan | d48a25e | 2021-04-30 09:50:58 -0700 | [diff] [blame] | 84 | using LastReadError = incfs::LastReadError; |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 85 | |
Yurii Zubrytskyi | 3fde572 | 2021-02-19 00:08:36 -0800 | [diff] [blame] | 86 | using ExistingMountCallback = android::base::function_ref< |
| 87 | void(std::string_view root, std::string_view backingDir, |
| 88 | std::span<std::pair<std::string_view, std::string_view>> binds)>; |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 89 | |
Yurii Zubrytskyi | 4cd2492 | 2021-03-24 00:46:29 -0700 | [diff] [blame] | 90 | using FileCallback = android::base::function_ref<bool(const Control& control, FileId fileId)>; |
| 91 | |
Yurii Zubrytskyi | 4375a74 | 2021-03-18 16:59:47 -0700 | [diff] [blame] | 92 | static std::string toString(FileId fileId); |
| 93 | |
Yurii Zubrytskyi | 4a25dfb | 2020-01-10 11:53:24 -0800 | [diff] [blame] | 94 | virtual ~IncFsWrapper() = default; |
Yurii Zubrytskyi | a5946f7 | 2021-02-17 14:24:14 -0800 | [diff] [blame] | 95 | virtual Features features() const = 0; |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 96 | virtual void listExistingMounts(const ExistingMountCallback& cb) const = 0; |
| 97 | virtual Control openMount(std::string_view path) const = 0; |
Yurii Zubrytskyi | 5f69292 | 2020-12-08 07:35:24 -0800 | [diff] [blame] | 98 | virtual Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs, |
| 99 | IncFsFd blocksWritten) const = 0; |
Songchun Fan | 20d6ef2 | 2020-03-03 09:47:15 -0800 | [diff] [blame] | 100 | virtual ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id, |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 101 | incfs::NewFileParams params) const = 0; |
Yurii Zubrytskyi | a5946f7 | 2021-02-17 14:24:14 -0800 | [diff] [blame] | 102 | virtual ErrorCode makeMappedFile(const Control& control, std::string_view path, int mode, |
| 103 | incfs::NewMappedFileParams params) const = 0; |
Songchun Fan | 20d6ef2 | 2020-03-03 09:47:15 -0800 | [diff] [blame] | 104 | virtual ErrorCode makeDir(const Control& control, std::string_view path, int mode) const = 0; |
Yurii Zubrytskyi | efebb45 | 2020-04-22 13:59:06 -0700 | [diff] [blame] | 105 | virtual ErrorCode makeDirs(const Control& control, std::string_view path, int mode) const = 0; |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 106 | virtual incfs::RawMetadata getMetadata(const Control& control, FileId fileid) const = 0; |
| 107 | virtual incfs::RawMetadata getMetadata(const Control& control, std::string_view path) const = 0; |
Songchun Fan | 20d6ef2 | 2020-03-03 09:47:15 -0800 | [diff] [blame] | 108 | virtual FileId getFileId(const Control& control, std::string_view path) const = 0; |
Songchun Fan | 374f765 | 2020-08-20 08:40:29 -0700 | [diff] [blame] | 109 | virtual std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks( |
| 110 | const Control& control, std::string_view path) const = 0; |
Yurii Zubrytskyi | 256a1a4 | 2021-03-18 14:21:54 -0700 | [diff] [blame] | 111 | virtual incfs::LoadingState isFileFullyLoaded(const Control& control, |
| 112 | std::string_view path) const = 0; |
Yurii Zubrytskyi | 4cd2492 | 2021-03-24 00:46:29 -0700 | [diff] [blame] | 113 | virtual incfs::LoadingState isFileFullyLoaded(const Control& control, FileId id) const = 0; |
Yurii Zubrytskyi | 256a1a4 | 2021-03-18 14:21:54 -0700 | [diff] [blame] | 114 | virtual incfs::LoadingState isEverythingFullyLoaded(const Control& control) const = 0; |
Songchun Fan | 20d6ef2 | 2020-03-03 09:47:15 -0800 | [diff] [blame] | 115 | virtual ErrorCode link(const Control& control, std::string_view from, |
| 116 | std::string_view to) const = 0; |
| 117 | virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0; |
Alex Buynytskyy | bc0a7e6 | 2020-08-25 12:45:22 -0700 | [diff] [blame] | 118 | virtual UniqueFd openForSpecialOps(const Control& control, FileId id) const = 0; |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 119 | virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0; |
Yurii Zubrytskyi | 4cd2492 | 2021-03-24 00:46:29 -0700 | [diff] [blame] | 120 | virtual ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const = 0; |
Alex Buynytskyy | 8ef61ae | 2020-05-08 16:18:52 -0700 | [diff] [blame] | 121 | virtual WaitResult waitForPendingReads( |
| 122 | const Control& control, std::chrono::milliseconds timeout, |
Alex Buynytskyy | c144cc4 | 2021-03-31 22:19:42 -0700 | [diff] [blame] | 123 | std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer) const = 0; |
Alex Buynytskyy | aa8e95e | 2020-12-14 21:50:04 -0800 | [diff] [blame] | 124 | virtual ErrorCode setUidReadTimeouts( |
| 125 | const Control& control, |
| 126 | const std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts) |
| 127 | const = 0; |
Yurii Zubrytskyi | 4cd2492 | 2021-03-24 00:46:29 -0700 | [diff] [blame] | 128 | virtual ErrorCode forEachFile(const Control& control, FileCallback cb) const = 0; |
| 129 | virtual ErrorCode forEachIncompleteFile(const Control& control, FileCallback cb) const = 0; |
Songchun Fan | f949c37 | 2021-04-27 11:26:25 -0700 | [diff] [blame] | 130 | virtual std::optional<Metrics> getMetrics(std::string_view sysfsName) const = 0; |
Songchun Fan | d48a25e | 2021-04-30 09:50:58 -0700 | [diff] [blame] | 131 | virtual std::optional<LastReadError> getLastReadError(const Control& control) const = 0; |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 132 | }; |
| 133 | |
Alex Buynytskyy | 96e350b | 2020-04-02 20:03:47 -0700 | [diff] [blame] | 134 | class AppOpsManagerWrapper { |
| 135 | public: |
| 136 | virtual ~AppOpsManagerWrapper() = default; |
Alex Buynytskyy | 1d89216 | 2020-04-03 23:00:19 -0700 | [diff] [blame] | 137 | virtual binder::Status checkPermission(const char* permission, const char* operation, |
| 138 | const char* package) const = 0; |
Songchun Fan | 374f765 | 2020-08-20 08:40:29 -0700 | [diff] [blame] | 139 | virtual void startWatchingMode(int32_t op, const String16& packageName, |
| 140 | const sp<IAppOpsCallback>& callback) = 0; |
Alex Buynytskyy | 1d89216 | 2020-04-03 23:00:19 -0700 | [diff] [blame] | 141 | virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0; |
Alex Buynytskyy | 96e350b | 2020-04-02 20:03:47 -0700 | [diff] [blame] | 142 | }; |
| 143 | |
Yurii Zubrytskyi | 8632140 | 2020-04-09 19:22:30 -0700 | [diff] [blame] | 144 | class JniWrapper { |
| 145 | public: |
| 146 | virtual ~JniWrapper() = default; |
| 147 | virtual void initializeForCurrentThread() const = 0; |
| 148 | }; |
| 149 | |
Alex Buynytskyy | cca2c11 | 2020-05-05 12:48:41 -0700 | [diff] [blame] | 150 | class LooperWrapper { |
| 151 | public: |
| 152 | virtual ~LooperWrapper() = default; |
| 153 | virtual int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback, |
| 154 | void* data) = 0; |
| 155 | virtual int removeFd(int fd) = 0; |
| 156 | virtual void wake() = 0; |
| 157 | virtual int pollAll(int timeoutMillis) = 0; |
| 158 | }; |
| 159 | |
Alex Buynytskyy | 46d3ddb | 2020-05-29 12:05:05 -0700 | [diff] [blame] | 160 | class TimedQueueWrapper { |
| 161 | public: |
| 162 | virtual ~TimedQueueWrapper() = default; |
| 163 | virtual void addJob(MountId id, Milliseconds after, Job what) = 0; |
| 164 | virtual void removeJobs(MountId id) = 0; |
| 165 | virtual void stop() = 0; |
| 166 | }; |
| 167 | |
Songchun Fan | 374f765 | 2020-08-20 08:40:29 -0700 | [diff] [blame] | 168 | class FsWrapper { |
| 169 | public: |
| 170 | virtual ~FsWrapper() = default; |
Yurii Zubrytskyi | 3fde572 | 2021-02-19 00:08:36 -0800 | [diff] [blame] | 171 | |
| 172 | using FileCallback = android::base::function_ref<bool(std::string_view)>; |
| 173 | virtual void listFilesRecursive(std::string_view directoryPath, FileCallback onFile) const = 0; |
Songchun Fan | 374f765 | 2020-08-20 08:40:29 -0700 | [diff] [blame] | 174 | }; |
| 175 | |
Alex Buynytskyy | 7e06d71 | 2021-03-09 19:24:23 -0800 | [diff] [blame] | 176 | class ClockWrapper { |
| 177 | public: |
| 178 | virtual ~ClockWrapper() = default; |
| 179 | virtual TimePoint now() const = 0; |
| 180 | }; |
| 181 | |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 182 | class ServiceManagerWrapper { |
| 183 | public: |
Yurii Zubrytskyi | 4a25dfb | 2020-01-10 11:53:24 -0800 | [diff] [blame] | 184 | virtual ~ServiceManagerWrapper() = default; |
| 185 | virtual std::unique_ptr<VoldServiceWrapper> getVoldService() = 0; |
Songchun Fan | 68645c4 | 2020-02-27 15:57:35 -0800 | [diff] [blame] | 186 | virtual std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() = 0; |
Yurii Zubrytskyi | 4a25dfb | 2020-01-10 11:53:24 -0800 | [diff] [blame] | 187 | virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0; |
Alex Buynytskyy | 96e350b | 2020-04-02 20:03:47 -0700 | [diff] [blame] | 188 | virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0; |
Yurii Zubrytskyi | 8632140 | 2020-04-09 19:22:30 -0700 | [diff] [blame] | 189 | virtual std::unique_ptr<JniWrapper> getJni() = 0; |
Alex Buynytskyy | cca2c11 | 2020-05-05 12:48:41 -0700 | [diff] [blame] | 190 | virtual std::unique_ptr<LooperWrapper> getLooper() = 0; |
Alex Buynytskyy | 46d3ddb | 2020-05-29 12:05:05 -0700 | [diff] [blame] | 191 | virtual std::unique_ptr<TimedQueueWrapper> getTimedQueue() = 0; |
Songchun Fan | a709859 | 2020-09-03 11:45:53 -0700 | [diff] [blame] | 192 | virtual std::unique_ptr<TimedQueueWrapper> getProgressUpdateJobQueue() = 0; |
Songchun Fan | 374f765 | 2020-08-20 08:40:29 -0700 | [diff] [blame] | 193 | virtual std::unique_ptr<FsWrapper> getFs() = 0; |
Alex Buynytskyy | 7e06d71 | 2021-03-09 19:24:23 -0800 | [diff] [blame] | 194 | virtual std::unique_ptr<ClockWrapper> getClock() = 0; |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 195 | }; |
| 196 | |
| 197 | // --- Real stuff --- |
| 198 | |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 199 | class RealServiceManager : public ServiceManagerWrapper { |
| 200 | public: |
Yurii Zubrytskyi | 8632140 | 2020-04-09 19:22:30 -0700 | [diff] [blame] | 201 | RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env); |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 202 | ~RealServiceManager() = default; |
Alex Buynytskyy | 96e350b | 2020-04-02 20:03:47 -0700 | [diff] [blame] | 203 | std::unique_ptr<VoldServiceWrapper> getVoldService() final; |
| 204 | std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final; |
| 205 | std::unique_ptr<IncFsWrapper> getIncFs() final; |
| 206 | std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final; |
Yurii Zubrytskyi | 8632140 | 2020-04-09 19:22:30 -0700 | [diff] [blame] | 207 | std::unique_ptr<JniWrapper> getJni() final; |
Alex Buynytskyy | cca2c11 | 2020-05-05 12:48:41 -0700 | [diff] [blame] | 208 | std::unique_ptr<LooperWrapper> getLooper() final; |
Alex Buynytskyy | 46d3ddb | 2020-05-29 12:05:05 -0700 | [diff] [blame] | 209 | std::unique_ptr<TimedQueueWrapper> getTimedQueue() final; |
Songchun Fan | a709859 | 2020-09-03 11:45:53 -0700 | [diff] [blame] | 210 | std::unique_ptr<TimedQueueWrapper> getProgressUpdateJobQueue() final; |
Songchun Fan | 374f765 | 2020-08-20 08:40:29 -0700 | [diff] [blame] | 211 | std::unique_ptr<FsWrapper> getFs() final; |
Alex Buynytskyy | 7e06d71 | 2021-03-09 19:24:23 -0800 | [diff] [blame] | 212 | std::unique_ptr<ClockWrapper> getClock() final; |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 213 | |
| 214 | private: |
| 215 | template <class INTERFACE> |
| 216 | sp<INTERFACE> getRealService(std::string_view serviceName) const; |
| 217 | sp<android::IServiceManager> mServiceManager; |
Yurii Zubrytskyi | 8632140 | 2020-04-09 19:22:30 -0700 | [diff] [blame] | 218 | JavaVM* const mJvm; |
Songchun Fan | 3c82a30 | 2019-11-29 14:23:45 -0800 | [diff] [blame] | 219 | }; |
| 220 | |
Yurii Zubrytskyi | 629051fd | 2020-04-17 23:13:47 -0700 | [diff] [blame] | 221 | } // namespace android::incremental |