blob: 7e85f9db70fd738d357b73b788981bfa086ed90d [file] [log] [blame]
Songchun Fan3c82a302019-11-29 14:23:45 -08001/*
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
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070017#define LOG_TAG "IncrementalService"
18
Songchun Fan3c82a302019-11-29 14:23:45 -080019#include "ServiceWrappers.h"
20
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070021#include <MountRegistry.h>
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070022#include <android-base/logging.h>
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070023#include <android/content/pm/IDataLoaderManager.h>
24#include <android/os/IVold.h>
25#include <binder/AppOpsManager.h>
Songchun Fan3c82a302019-11-29 14:23:45 -080026#include <utils/String16.h>
27
Songchun Fan374f7652020-08-20 08:40:29 -070028#include <filesystem>
Alex Buynytskyy46d3ddb2020-05-29 12:05:05 -070029#include <thread>
30
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070031#include "IncrementalServiceValidation.h"
32
Songchun Fan3c82a302019-11-29 14:23:45 -080033using namespace std::literals;
34
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070035namespace android::incremental {
Songchun Fan3c82a302019-11-29 14:23:45 -080036
37static constexpr auto kVoldServiceName = "vold"sv;
Songchun Fan68645c42020-02-27 15:57:35 -080038static constexpr auto kDataLoaderManagerName = "dataloader_manager"sv;
Songchun Fan3c82a302019-11-29 14:23:45 -080039
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070040class RealVoldService : public VoldServiceWrapper {
41public:
Yurii Zubrytskyi510037b2020-04-22 15:46:21 -070042 RealVoldService(sp<os::IVold> vold) : mInterface(std::move(vold)) {}
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070043 ~RealVoldService() = default;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070044 binder::Status mountIncFs(
45 const std::string& backingPath, const std::string& targetDir, int32_t flags,
46 os::incremental::IncrementalFileSystemControlParcel* _aidl_return) const final {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070047 return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return);
48 }
49 binder::Status unmountIncFs(const std::string& dir) const final {
50 return mInterface->unmountIncFs(dir);
51 }
52 binder::Status bindMount(const std::string& sourceDir,
53 const std::string& targetDir) const final {
54 return mInterface->bindMount(sourceDir, targetDir);
55 }
56 binder::Status setIncFsMountOptions(
57 const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
58 bool enableReadLogs) const final {
59 return mInterface->setIncFsMountOptions(control, enableReadLogs);
60 }
61
62private:
63 sp<os::IVold> mInterface;
64};
65
66class RealDataLoaderManager : public DataLoaderManagerWrapper {
67public:
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070068 RealDataLoaderManager(sp<content::pm::IDataLoaderManager> manager)
69 : mInterface(std::move(manager)) {}
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070070 ~RealDataLoaderManager() = default;
Alex Buynytskyyea1390f2020-04-22 16:08:50 -070071 binder::Status bindToDataLoader(MountId mountId,
72 const content::pm::DataLoaderParamsParcel& params,
Alex Buynytskyyb19ee3e2021-02-06 20:31:43 -080073 int bindDelayMs,
Alex Buynytskyyea1390f2020-04-22 16:08:50 -070074 const sp<content::pm::IDataLoaderStatusListener>& listener,
75 bool* _aidl_return) const final {
Alex Buynytskyyb19ee3e2021-02-06 20:31:43 -080076 return mInterface->bindToDataLoader(mountId, params, bindDelayMs, listener, _aidl_return);
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070077 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070078 binder::Status getDataLoader(MountId mountId,
79 sp<content::pm::IDataLoader>* _aidl_return) const final {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070080 return mInterface->getDataLoader(mountId, _aidl_return);
81 }
Alex Buynytskyyea1390f2020-04-22 16:08:50 -070082 binder::Status unbindFromDataLoader(MountId mountId) const final {
83 return mInterface->unbindFromDataLoader(mountId);
Yurii Zubrytskyi86321402020-04-09 19:22:30 -070084 }
85
86private:
87 sp<content::pm::IDataLoaderManager> mInterface;
88};
89
90class RealAppOpsManager : public AppOpsManagerWrapper {
91public:
92 ~RealAppOpsManager() = default;
93 binder::Status checkPermission(const char* permission, const char* operation,
94 const char* package) const final {
95 return android::incremental::CheckPermissionForDataDelivery(permission, operation, package);
96 }
97 void startWatchingMode(int32_t op, const String16& packageName,
98 const sp<IAppOpsCallback>& callback) final {
99 mAppOpsManager.startWatchingMode(op, packageName, callback);
100 }
101 void stopWatchingMode(const sp<IAppOpsCallback>& callback) final {
102 mAppOpsManager.stopWatchingMode(callback);
103 }
104
105private:
106 android::AppOpsManager mAppOpsManager;
107};
108
109class RealJniWrapper final : public JniWrapper {
110public:
111 RealJniWrapper(JavaVM* jvm);
112 void initializeForCurrentThread() const final;
113
114 static JavaVM* getJvm(JNIEnv* env);
115
116private:
117 JavaVM* const mJvm;
118};
119
Alex Buynytskyycca2c112020-05-05 12:48:41 -0700120class RealLooperWrapper final : public LooperWrapper {
121public:
122 int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback,
123 void* data) final {
124 return mLooper.addFd(fd, ident, events, callback, data);
125 }
126 int removeFd(int fd) final { return mLooper.removeFd(fd); }
127 void wake() final { return mLooper.wake(); }
128 int pollAll(int timeoutMillis) final { return mLooper.pollAll(timeoutMillis); }
129
130private:
131 struct Looper : public android::Looper {
132 Looper() : android::Looper(/*allowNonCallbacks=*/false) {}
133 ~Looper() {}
134 } mLooper;
135};
136
Yurii Zubrytskyi4375a742021-03-18 16:59:47 -0700137std::string IncFsWrapper::toString(FileId fileId) {
138 return incfs::toString(fileId);
139}
140
Yurii Zubrytskyia5946f72021-02-17 14:24:14 -0800141class RealIncFs final : public IncFsWrapper {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700142public:
143 RealIncFs() = default;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700144 ~RealIncFs() final = default;
Yurii Zubrytskyia5946f72021-02-17 14:24:14 -0800145 Features features() const final { return incfs::features(); }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700146 void listExistingMounts(const ExistingMountCallback& cb) const final {
147 for (auto mount : incfs::defaultMountRegistry().copyMounts()) {
148 auto binds = mount.binds(); // span() doesn't like rvalue containers, needs to save it.
149 cb(mount.root(), mount.backingDir(), binds);
150 }
151 }
152 Control openMount(std::string_view path) const final { return incfs::open(path); }
Yurii Zubrytskyi5f692922020-12-08 07:35:24 -0800153 Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs,
154 IncFsFd blocksWritten) const final {
155 return incfs::createControl(cmd, pendingReads, logs, blocksWritten);
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700156 }
157 ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id,
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700158 incfs::NewFileParams params) const final {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700159 return incfs::makeFile(control, path, mode, id, params);
160 }
Yurii Zubrytskyia5946f72021-02-17 14:24:14 -0800161 ErrorCode makeMappedFile(const Control& control, std::string_view path, int mode,
162 incfs::NewMappedFileParams params) const final {
163 return incfs::makeMappedFile(control, path, mode, params);
164 }
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700165 ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final {
166 return incfs::makeDir(control, path, mode);
167 }
Yurii Zubrytskyiefebb452020-04-22 13:59:06 -0700168 ErrorCode makeDirs(const Control& control, std::string_view path, int mode) const final {
169 return incfs::makeDirs(control, path, mode);
170 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700171 incfs::RawMetadata getMetadata(const Control& control, FileId fileid) const final {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700172 return incfs::getMetadata(control, fileid);
173 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700174 incfs::RawMetadata getMetadata(const Control& control, std::string_view path) const final {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700175 return incfs::getMetadata(control, path);
176 }
177 FileId getFileId(const Control& control, std::string_view path) const final {
178 return incfs::getFileId(control, path);
179 }
Songchun Fan374f7652020-08-20 08:40:29 -0700180 std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
181 const Control& control, std::string_view path) const final {
Yurii Zubrytskyi4375a742021-03-18 16:59:47 -0700182 if (incfs::features() & Features::v2) {
183 const auto counts = incfs::getBlockCount(control, path);
184 if (!counts) {
185 return {-errno, -errno};
186 }
187 return {counts->filledDataBlocks + counts->filledHashBlocks,
188 counts->totalDataBlocks + counts->totalHashBlocks};
189 }
Songchun Fan374f7652020-08-20 08:40:29 -0700190 const auto fileId = incfs::getFileId(control, path);
191 const auto fd = incfs::openForSpecialOps(control, fileId);
192 int res = fd.get();
193 if (!fd.ok()) {
194 return {res, res};
195 }
196 const auto ranges = incfs::getFilledRanges(res);
197 res = ranges.first;
198 if (res) {
199 return {res, res};
200 }
201 const auto totalBlocksCount = ranges.second.internalRawRanges().endIndex;
202 int filledBlockCount = 0;
203 for (const auto& dataRange : ranges.second.dataRanges()) {
204 filledBlockCount += dataRange.size();
205 }
206 for (const auto& hashRange : ranges.second.hashRanges()) {
207 filledBlockCount += hashRange.size();
208 }
209 return {filledBlockCount, totalBlocksCount};
210 }
Yurii Zubrytskyi256a1a42021-03-18 14:21:54 -0700211 incfs::LoadingState isFileFullyLoaded(const Control& control,
212 std::string_view path) const final {
213 return incfs::isFullyLoaded(control, path);
214 }
215 incfs::LoadingState isEverythingFullyLoaded(const Control& control) const final {
216 return incfs::isEverythingFullyLoaded(control);
217 }
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700218 ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
219 return incfs::link(control, from, to);
220 }
221 ErrorCode unlink(const Control& control, std::string_view path) const final {
222 return incfs::unlink(control, path);
223 }
Alex Buynytskyybc0a7e62020-08-25 12:45:22 -0700224 incfs::UniqueFd openForSpecialOps(const Control& control, FileId id) const final {
225 return incfs::openForSpecialOps(control, id);
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700226 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700227 ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
228 return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700229 }
Yurii Zubrytskyi65fc38a2021-03-17 13:18:30 -0700230 ErrorCode reserveSpace(const Control& control, std::string_view path,
231 IncFsSize size) const final {
232 return incfs::reserveSpace(control, path, size);
233 }
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -0700234 WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
235 std::vector<incfs::ReadInfo>* pendingReadsBuffer) const final {
236 return incfs::waitForPendingReads(control, timeout, pendingReadsBuffer);
237 }
Alex Buynytskyyaa8e95e2020-12-14 21:50:04 -0800238 ErrorCode setUidReadTimeouts(const Control& control,
239 const std::vector<android::os::incremental::PerUidReadTimeouts>&
240 perUidReadTimeouts) const final {
Alex Buynytskyyfe6b4c02021-01-26 13:29:24 -0800241 std::vector<incfs::UidReadTimeouts> timeouts;
242 timeouts.resize(perUidReadTimeouts.size());
243 for (int i = 0, size = perUidReadTimeouts.size(); i < size; ++i) {
244 auto&& timeout = timeouts[i];
245 const auto& perUidTimeout = perUidReadTimeouts[i];
246 timeout.uid = perUidTimeout.uid;
247 timeout.minTimeUs = perUidTimeout.minTimeUs;
248 timeout.minPendingTimeUs = perUidTimeout.minPendingTimeUs;
249 timeout.maxPendingTimeUs = perUidTimeout.maxPendingTimeUs;
250 }
Alex Buynytskyy07694ed2021-01-27 06:58:55 -0800251
Alex Buynytskyyfe6b4c02021-01-26 13:29:24 -0800252 return incfs::setUidReadTimeouts(control, timeouts);
Alex Buynytskyyaa8e95e2020-12-14 21:50:04 -0800253 }
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700254};
255
Alex Buynytskyy46d3ddb2020-05-29 12:05:05 -0700256static JNIEnv* getOrAttachJniEnv(JavaVM* jvm);
257
258class RealTimedQueueWrapper : public TimedQueueWrapper {
259public:
260 RealTimedQueueWrapper(JavaVM* jvm) {
261 mThread = std::thread([this, jvm]() {
262 (void)getOrAttachJniEnv(jvm);
263 runTimers();
264 });
265 }
266 ~RealTimedQueueWrapper() final {
267 CHECK(!mRunning) << "call stop first";
268 CHECK(!mThread.joinable()) << "call stop first";
269 }
270
271 void addJob(MountId id, Milliseconds after, Job what) final {
272 const auto now = Clock::now();
273 {
274 std::unique_lock lock(mMutex);
275 mJobs.insert(TimedJob{id, now + after, std::move(what)});
276 }
277 mCondition.notify_all();
278 }
279 void removeJobs(MountId id) final {
280 std::unique_lock lock(mMutex);
281 std::erase_if(mJobs, [id](auto&& item) { return item.id == id; });
282 }
283 void stop() final {
284 {
285 std::unique_lock lock(mMutex);
286 mRunning = false;
287 }
288 mCondition.notify_all();
289 mThread.join();
290 mJobs.clear();
291 }
292
293private:
294 void runTimers() {
295 static constexpr TimePoint kInfinityTs{Clock::duration::max()};
296 TimePoint nextJobTs = kInfinityTs;
297 std::unique_lock lock(mMutex);
298 for (;;) {
299 mCondition.wait_until(lock, nextJobTs, [this, nextJobTs]() {
300 const auto now = Clock::now();
301 const auto firstJobTs = !mJobs.empty() ? mJobs.begin()->when : kInfinityTs;
302 return !mRunning || firstJobTs <= now || firstJobTs < nextJobTs;
303 });
304 if (!mRunning) {
305 return;
306 }
307
308 const auto now = Clock::now();
309 auto it = mJobs.begin();
310 // Always acquire begin(). We can't use it after unlock as mTimedJobs can change.
311 for (; it != mJobs.end() && it->when <= now; it = mJobs.begin()) {
Yurii Zubrytskyi3fde5722021-02-19 00:08:36 -0800312 auto jobNode = mJobs.extract(it);
Alex Buynytskyy46d3ddb2020-05-29 12:05:05 -0700313
314 lock.unlock();
Yurii Zubrytskyi3fde5722021-02-19 00:08:36 -0800315 jobNode.value().what();
Alex Buynytskyy46d3ddb2020-05-29 12:05:05 -0700316 lock.lock();
317 }
318 nextJobTs = it != mJobs.end() ? it->when : kInfinityTs;
319 }
320 }
321
322 struct TimedJob {
323 MountId id;
324 TimePoint when;
325 Job what;
326 friend bool operator<(const TimedJob& lhs, const TimedJob& rhs) {
327 return lhs.when < rhs.when;
328 }
329 };
330 bool mRunning = true;
331 std::set<TimedJob> mJobs;
332 std::condition_variable mCondition;
333 std::mutex mMutex;
334 std::thread mThread;
335};
336
Yurii Zubrytskyi3fde5722021-02-19 00:08:36 -0800337class RealFsWrapper final : public FsWrapper {
Songchun Fan374f7652020-08-20 08:40:29 -0700338public:
339 RealFsWrapper() = default;
340 ~RealFsWrapper() = default;
341
Yurii Zubrytskyi3fde5722021-02-19 00:08:36 -0800342 void listFilesRecursive(std::string_view directoryPath, FileCallback onFile) const final {
Songchun Fan374f7652020-08-20 08:40:29 -0700343 for (const auto& entry : std::filesystem::recursive_directory_iterator(directoryPath)) {
344 if (!entry.is_regular_file()) {
345 continue;
346 }
Yurii Zubrytskyi3fde5722021-02-19 00:08:36 -0800347 if (!onFile(entry.path().native())) {
348 break;
349 }
Songchun Fan374f7652020-08-20 08:40:29 -0700350 }
Songchun Fan374f7652020-08-20 08:40:29 -0700351 }
352};
353
Alex Buynytskyy7e06d712021-03-09 19:24:23 -0800354class RealClockWrapper final : public ClockWrapper {
355public:
356 RealClockWrapper() = default;
357 ~RealClockWrapper() = default;
358
359 TimePoint now() const final { return Clock::now(); }
360};
361
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700362RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
363 : mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {}
Songchun Fan3c82a302019-11-29 14:23:45 -0800364
365template <class INTERFACE>
366sp<INTERFACE> RealServiceManager::getRealService(std::string_view serviceName) const {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800367 sp<IBinder> binder =
368 mServiceManager->getService(String16(serviceName.data(), serviceName.size()));
369 if (!binder) {
370 return nullptr;
Songchun Fan3c82a302019-11-29 14:23:45 -0800371 }
372 return interface_cast<INTERFACE>(binder);
373}
374
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800375std::unique_ptr<VoldServiceWrapper> RealServiceManager::getVoldService() {
Songchun Fan3c82a302019-11-29 14:23:45 -0800376 sp<os::IVold> vold = RealServiceManager::getRealService<os::IVold>(kVoldServiceName);
377 if (vold != 0) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800378 return std::make_unique<RealVoldService>(vold);
Songchun Fan3c82a302019-11-29 14:23:45 -0800379 }
380 return nullptr;
381}
382
Songchun Fan68645c42020-02-27 15:57:35 -0800383std::unique_ptr<DataLoaderManagerWrapper> RealServiceManager::getDataLoaderManager() {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700384 sp<content::pm::IDataLoaderManager> manager =
385 RealServiceManager::getRealService<content::pm::IDataLoaderManager>(
386 kDataLoaderManagerName);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800387 if (manager) {
Songchun Fan68645c42020-02-27 15:57:35 -0800388 return std::make_unique<RealDataLoaderManager>(manager);
Songchun Fan3c82a302019-11-29 14:23:45 -0800389 }
390 return nullptr;
391}
392
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800393std::unique_ptr<IncFsWrapper> RealServiceManager::getIncFs() {
394 return std::make_unique<RealIncFs>();
Songchun Fan3c82a302019-11-29 14:23:45 -0800395}
396
Alex Buynytskyy96e350b2020-04-02 20:03:47 -0700397std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() {
398 return std::make_unique<RealAppOpsManager>();
399}
400
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700401std::unique_ptr<JniWrapper> RealServiceManager::getJni() {
402 return std::make_unique<RealJniWrapper>(mJvm);
403}
404
Alex Buynytskyycca2c112020-05-05 12:48:41 -0700405std::unique_ptr<LooperWrapper> RealServiceManager::getLooper() {
406 return std::make_unique<RealLooperWrapper>();
407}
408
Alex Buynytskyy46d3ddb2020-05-29 12:05:05 -0700409std::unique_ptr<TimedQueueWrapper> RealServiceManager::getTimedQueue() {
410 return std::make_unique<RealTimedQueueWrapper>(mJvm);
411}
412
Songchun Fana7098592020-09-03 11:45:53 -0700413std::unique_ptr<TimedQueueWrapper> RealServiceManager::getProgressUpdateJobQueue() {
414 return std::make_unique<RealTimedQueueWrapper>(mJvm);
415}
416
Songchun Fan374f7652020-08-20 08:40:29 -0700417std::unique_ptr<FsWrapper> RealServiceManager::getFs() {
418 return std::make_unique<RealFsWrapper>();
419}
420
Alex Buynytskyy7e06d712021-03-09 19:24:23 -0800421std::unique_ptr<ClockWrapper> RealServiceManager::getClock() {
422 return std::make_unique<RealClockWrapper>();
423}
424
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700425static JavaVM* getJavaVm(JNIEnv* env) {
426 CHECK(env);
427 JavaVM* jvm = nullptr;
428 env->GetJavaVM(&jvm);
429 CHECK(jvm);
430 return jvm;
431}
432
433static JNIEnv* getJniEnv(JavaVM* vm) {
434 JNIEnv* env;
435 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
436 return nullptr;
437 }
438 return env;
439}
440
441static JNIEnv* getOrAttachJniEnv(JavaVM* jvm) {
442 if (!jvm) {
443 LOG(ERROR) << "No JVM instance";
444 return nullptr;
445 }
446
447 JNIEnv* env = getJniEnv(jvm);
448 if (!env) {
449 int result = jvm->AttachCurrentThread(&env, nullptr);
450 if (result != JNI_OK) {
451 LOG(ERROR) << "JVM thread attach failed: " << result;
452 return nullptr;
453 }
454 struct VmDetacher {
455 VmDetacher(JavaVM* vm) : mVm(vm) {}
456 ~VmDetacher() { mVm->DetachCurrentThread(); }
457
458 private:
459 JavaVM* const mVm;
460 };
461 static thread_local VmDetacher detacher(jvm);
462 }
463
464 return env;
465}
466
467RealJniWrapper::RealJniWrapper(JavaVM* jvm) : mJvm(jvm) {
468 CHECK(!!mJvm) << "JVM is unavailable";
469}
470
471void RealJniWrapper::initializeForCurrentThread() const {
472 (void)getOrAttachJniEnv(mJvm);
473}
474
475JavaVM* RealJniWrapper::getJvm(JNIEnv* env) {
476 return getJavaVm(env);
477}
478
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700479} // namespace android::incremental