blob: 4e49302debcd85f1ffef8f4630515fd08447b2b1 [file] [log] [blame]
Songchun Fan4f0688b2019-12-05 15:03:22 -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
17#define ATRACE_TAG ATRACE_TAG_ADB
18#define LOG_TAG "NativeAdbDataLoaderService"
19
20#include <android-base/file.h>
21#include <android-base/logging.h>
22#include <android-base/properties.h>
23#include <android-base/stringprintf.h>
24#include <android-base/thread_annotations.h>
25#include <android-base/unique_fd.h>
26#include <cutils/trace.h>
27#include <fcntl.h>
28#include <sys/eventfd.h>
29#include <sys/poll.h>
30#include <sys/stat.h>
31#include <unistd.h>
32#include <utils/Log.h>
33
34#include <charconv>
35#include <string>
36#include <thread>
37#include <type_traits>
38#include <unordered_map>
39#include <unordered_set>
40
41#include "dataloader.h"
42
43#ifndef _WIN32
44#include <endian.h>
45#include <sys/stat.h>
46#include <unistd.h>
47#else
48#define be32toh(x) _byteswap_ulong(x)
49#define be16toh(x) _byteswap_ushort(x)
50#endif
51
52namespace {
53
54using android::base::unique_fd;
55
56using namespace std::literals;
57
58using BlockSize = int16_t;
59using FileId = int16_t;
60using BlockIdx = int32_t;
61using NumBlocks = int32_t;
62using CompressionType = int16_t;
63using RequestType = int16_t;
64
65static constexpr int COMMAND_SIZE = 2 + 2 + 4; // bytes
66static constexpr int HEADER_SIZE = 2 + 2 + 4 + 2; // bytes
67static constexpr std::string_view OKAY = "OKAY"sv;
68
69static constexpr auto PollTimeoutMs = 5000;
70
71static constexpr auto ReadLogBufferSize = 128 * 1024 * 1024;
72static constexpr auto ReadLogMaxEntrySize = 128;
73
74struct BlockHeader {
75 FileId fileId = -1;
76 CompressionType compressionType = -1;
77 BlockIdx blockIdx = -1;
78 BlockSize blockSize = -1;
79} __attribute__((packed));
80
81static_assert(sizeof(BlockHeader) == HEADER_SIZE);
82
83static constexpr RequestType EXIT = 0;
84static constexpr RequestType BLOCK_MISSING = 1;
85static constexpr RequestType PREFETCH = 2;
86
87struct RequestCommand {
88 RequestType requestType;
89 FileId fileId;
90 BlockIdx blockIdx;
91} __attribute__((packed));
92
93static_assert(COMMAND_SIZE == sizeof(RequestCommand));
94
95static bool sendRequest(int fd,
96 RequestType requestType,
97 FileId fileId = -1,
98 BlockIdx blockIdx = -1) {
99 const RequestCommand command{
100 .requestType = static_cast<int16_t>(be16toh(requestType)),
101 .fileId = static_cast<int16_t>(be16toh(fileId)),
102 .blockIdx = static_cast<int32_t>(be32toh(blockIdx))};
103 return android::base::WriteFully(fd, &command, sizeof(command));
104}
105
106static int waitForDataOrSignal(int fd, int event_fd) {
107 struct pollfd pfds[2] = {{fd, POLLIN, 0}, {event_fd, POLLIN, 0}};
108 // Wait indefinitely until either data is ready or stop signal is received
109 int res = poll(pfds, 2, PollTimeoutMs);
110 if (res <= 0) {
111 return res;
112 }
113 // First check if there is a stop signal
114 if (pfds[1].revents == POLLIN) {
115 return event_fd;
116 }
117 // Otherwise check if incoming data is ready
118 if (pfds[0].revents == POLLIN) {
119 return fd;
120 }
121 return -1;
122}
123
124static bool readChunk(int fd, std::vector<uint8_t>& data) {
125 int32_t size;
126 if (!android::base::ReadFully(fd, &size, sizeof(size))) {
127 return false;
128 }
129 size = int32_t(be32toh(size));
130 if (size <= 0) {
131 return false;
132 }
133 data.resize(size);
134 return android::base::ReadFully(fd, data.data(), data.size());
135}
136
137static BlockHeader readHeader(std::span<uint8_t>& data) {
138 BlockHeader header;
139 if (data.size() < sizeof(header)) {
140 return header;
141 }
142
143 header.fileId = static_cast<FileId>(
144 be16toh(*reinterpret_cast<uint16_t*>(&data[0])));
145 header.compressionType = static_cast<CompressionType>(
146 be16toh(*reinterpret_cast<uint16_t*>(&data[2])));
147 header.blockIdx = static_cast<BlockIdx>(
148 be32toh(*reinterpret_cast<uint32_t*>(&data[4])));
149 header.blockSize = static_cast<BlockSize>(
150 be16toh(*reinterpret_cast<uint16_t*>(&data[8])));
151 data = data.subspan(sizeof(header));
152
153 return header;
154}
155
156static std::string extractPackageName(const std::string& staticArgs) {
157 static constexpr auto kPrefix = "package="sv;
158 static constexpr auto kSuffix = "&"sv;
159
160 const auto startPos = staticArgs.find(kPrefix);
161 if (startPos == staticArgs.npos || startPos + kPrefix.size() >= staticArgs.size()) {
162 return {};
163 }
164 const auto endPos = staticArgs.find(kSuffix, startPos + kPrefix.size());
165 return staticArgs.substr(startPos + kPrefix.size(),
166 endPos == staticArgs.npos ? staticArgs.npos
167 : (endPos - (startPos + kPrefix.size())));
168}
169
170class AdbDataLoader : public android::dataloader::DataLoader {
171private:
172 // Lifecycle.
173 bool onCreate(const android::dataloader::DataLoaderParams& params,
174 android::dataloader::FilesystemConnectorPtr ifs,
175 android::dataloader::StatusListenerPtr statusListener,
176 android::dataloader::ServiceConnectorPtr,
177 android::dataloader::ServiceParamsPtr) final {
178 CHECK(ifs) << "ifs can't be null";
179 CHECK(statusListener) << "statusListener can't be null";
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800180 ALOGE("[AdbDataLoader] onCreate: %d/%s/%s/%s/%d", params.type(), params.packageName().c_str(), params.className().c_str(), params.arguments().c_str(), (int)params.dynamicArgs().size());
Songchun Fan4f0688b2019-12-05 15:03:22 -0800181
182 if (params.dynamicArgs().empty()) {
183 ALOGE("[AdbDataLoader] Invalid DataLoaderParams. Need in/out FDs.");
184 return false;
185 }
186 for (auto const& namedFd : params.dynamicArgs()) {
187 if (namedFd.name == "inFd") {
188 mInFd.reset(dup(namedFd.fd));
189 }
190 if (namedFd.name == "outFd") {
191 mOutFd.reset(dup(namedFd.fd));
192 }
193 }
194 if (mInFd < 0 || mOutFd < 0) {
195 ALOGE("[AdbDataLoader] Failed to dup FDs.");
196 return false;
197 }
198
199 mEventFd.reset(eventfd(0, EFD_CLOEXEC));
200 if (mEventFd < 0) {
201 ALOGE("[AdbDataLoader] Failed to create eventfd.");
202 return false;
203 }
204
205 std::string logFile;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800206 if (const auto packageName = extractPackageName(params.arguments()); !packageName.empty()) {
Songchun Fan4f0688b2019-12-05 15:03:22 -0800207 logFile = android::base::GetProperty("adb.readlog." + packageName, "");
208 }
209 if (logFile.empty()) {
210 logFile = android::base::GetProperty("adb.readlog", "");
211 }
212 if (!logFile.empty()) {
213 int flags = O_WRONLY | O_CREAT | O_CLOEXEC;
214 mReadLogFd.reset(
215 TEMP_FAILURE_RETRY(open(logFile.c_str(), flags, 0666)));
216 }
217
218 mIfs = ifs;
219 mStatusListener = statusListener;
220 ALOGE("[AdbDataLoader] Successfully created data loader.");
221 return true;
222 }
223
224 bool onStart() final {
225 char okay_buf[OKAY.size()];
226 if (!android::base::ReadFully(mInFd, okay_buf, OKAY.size())) {
227 ALOGE("[AdbDataLoader] Failed to receive OKAY. Abort.");
228 return false;
229 }
230 if (std::string_view(okay_buf, OKAY.size()) != OKAY) {
231 ALOGE("[AdbDataLoader] Received '%.*s', expecting '%.*s'",
232 (int)OKAY.size(), okay_buf, (int)OKAY.size(), OKAY.data());
233 return false;
234 }
235
236 mReceiverThread = std::thread([this]() { receiver(); });
237 ALOGI("[AdbDataLoader] started loading...");
238 return true;
239 }
240
241 void onStop() final {
242 mStopReceiving = true;
243 eventfd_write(mEventFd, 1);
244 if (mReceiverThread.joinable()) {
245 mReceiverThread.join();
246 }
247 }
248
249 void onDestroy() final {
250 ALOGE("[AdbDataLoader] Sending EXIT to server.");
251 sendRequest(mOutFd, EXIT);
252 // Make sure the receiver thread was stopped
253 CHECK(!mReceiverThread.joinable());
254
255 mInFd.reset();
256 mOutFd.reset();
257
258 mNodeToMetaMap.clear();
259 mIdToNodeMap.clear();
260
261 flushReadLog();
262 mReadLogFd.reset();
263 }
264
265 // IFS callbacks.
266 void onPendingReads(const android::dataloader::PendingReads& pendingReads) final {
267 std::lock_guard lock{mMapsMutex};
268 CHECK(mIfs);
269 for (auto&& pendingRead : pendingReads) {
270 const android::dataloader::Inode ino = pendingRead.file_ino;
271 const auto blockIdx =
272 static_cast<BlockIdx>(pendingRead.block_index);
273 /*
274 ALOGI("[AdbDataLoader] Missing: %d", (int) blockIdx);
275 */
276 auto fileIdOr = getFileId(ino);
277 if (!fileIdOr) {
278 ALOGE("[AdbDataLoader] Failed to handle event for inode=%d. "
279 "Ignore.",
280 static_cast<int>(ino));
281 continue;
282 }
283 const FileId fileId = *fileIdOr;
284 if (mRequestedFiles.insert(fileId).second) {
285 if (!sendRequest(mOutFd, PREFETCH, fileId, blockIdx)) {
286 ALOGE("[AdbDataLoader] Failed to request prefetch for "
287 "inode=%d. Ignore.",
288 static_cast<int>(ino));
289 mRequestedFiles.erase(fileId);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800290 mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
Songchun Fan4f0688b2019-12-05 15:03:22 -0800291 }
292 }
293 sendRequest(mOutFd, BLOCK_MISSING, fileId, blockIdx);
294 }
295 }
296
297 struct TracedRead {
298 uint64_t timestampUs;
299 uint64_t fileIno;
300 uint32_t firstBlockIdx;
301 uint32_t count;
302 };
303 void onPageReads(const android::dataloader::PageReads& pageReads) final {
304 auto trace = atrace_is_tag_enabled(ATRACE_TAG);
305 auto log = mReadLogFd != -1;
306 if (CC_LIKELY(!(trace || log))) {
307 return;
308 }
309
310 TracedRead last = {0, 0, 0, 0};
311 std::lock_guard lock{mMapsMutex};
312 for (auto&& read : pageReads) {
313 if (read.file_ino != last.fileIno ||
314 read.block_index != last.firstBlockIdx + last.count) {
315 traceOrLogRead(last, trace, log);
316 last = {read.timestamp_us, read.file_ino, read.block_index, 1};
317 } else {
318 ++last.count;
319 }
320 }
321 traceOrLogRead(last, trace, log);
322 }
323 void onFileCreated(android::dataloader::Inode inode, const android::dataloader::RawMetadata& metadata) {
324 }
325
326private:
327 void receiver() {
328 std::vector<uint8_t> data;
329 std::vector<incfs_new_data_block> instructions;
330 while (!mStopReceiving) {
331 const int res = waitForDataOrSignal(mInFd, mEventFd);
332 if (res == 0) {
333 flushReadLog();
334 continue;
335 }
336 if (res < 0) {
337 ALOGE("[AdbDataLoader] failed to poll. Abort.");
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800338 mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
Songchun Fan4f0688b2019-12-05 15:03:22 -0800339 break;
340 }
341 if (res == mEventFd) {
342 ALOGE("[AdbDataLoader] received stop signal. Exit.");
343 break;
344 }
345 if (!readChunk(mInFd, data)) {
346 ALOGE("[AdbDataLoader] failed to read a message. Abort.");
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800347 mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
Songchun Fan4f0688b2019-12-05 15:03:22 -0800348 break;
349 }
350 auto remainingData = std::span(data);
351 while (!remainingData.empty()) {
352 auto header = readHeader(remainingData);
353 if (header.fileId == -1 && header.compressionType == 0 &&
354 header.blockIdx == 0 && header.blockSize == 0) {
355 ALOGI("[AdbDataLoader] stop signal received. Sending "
356 "exit command (remaining bytes: %d).",
357 int(remainingData.size()));
358
359 sendRequest(mOutFd, EXIT);
360 mStopReceiving = true;
361 break;
362 }
363 if (header.fileId < 0 || header.blockSize <= 0 ||
364 header.compressionType < 0 || header.blockIdx < 0) {
365 ALOGE("[AdbDataLoader] invalid header received. Abort.");
366 mStopReceiving = true;
367 break;
368 }
369 const android::dataloader::Inode ino = mIdToNodeMap[header.fileId];
370 if (!ino) {
371 ALOGE("Unknown data destination for file ID %d. "
372 "Ignore.",
373 header.fileId);
374 continue;
375 }
376 auto inst = incfs_new_data_block{
377 .file_ino = static_cast<__aligned_u64>(ino),
378 .block_index = static_cast<uint32_t>(header.blockIdx),
379 .data_len = static_cast<uint16_t>(header.blockSize),
380 .data = reinterpret_cast<uint64_t>(
381 remainingData.data()),
382 .compression =
383 static_cast<uint8_t>(header.compressionType)};
384 instructions.push_back(inst);
385 remainingData = remainingData.subspan(header.blockSize);
386 }
387 writeInstructions(instructions);
388 }
389 writeInstructions(instructions);
390 flushReadLog();
391 }
392
393 void writeInstructions(std::vector<incfs_new_data_block>& instructions) {
394 auto res = this->mIfs->writeBlocks(instructions.data(),
395 instructions.size());
396 if (res != instructions.size()) {
397 ALOGE("[AdbDataLoader] failed to write data to Incfs (res=%d when "
398 "expecting %d)",
399 res, int(instructions.size()));
400 }
401 instructions.clear();
402 }
403
404 struct MetaPair {
405 android::dataloader::RawMetadata meta;
406 FileId fileId;
407 };
408
409 MetaPair* updateMapsForFile(android::dataloader::Inode ino) {
410 android::dataloader::RawMetadata meta = mIfs->getRawMetadata(ino);
411 FileId fileId;
412 auto res =
413 std::from_chars(meta.data(), meta.data() + meta.size(), fileId);
414 if (res.ec != std::errc{} || fileId < 0) {
415 ALOGE("[AdbDataLoader] Invalid metadata for inode=%d (%s)",
416 static_cast<int>(ino), meta.data());
417 return nullptr;
418 }
419 mIdToNodeMap[fileId] = ino;
420 auto& metaPair = mNodeToMetaMap[ino];
421 metaPair.meta = std::move(meta);
422 metaPair.fileId = fileId;
423 return &metaPair;
424 }
425
426 android::dataloader::RawMetadata* getMeta(android::dataloader::Inode ino) {
427 auto it = mNodeToMetaMap.find(ino);
428 if (it != mNodeToMetaMap.end()) {
429 return &it->second.meta;
430 }
431
432 auto metaPair = updateMapsForFile(ino);
433 if (!metaPair) {
434 return nullptr;
435 }
436
437 return &metaPair->meta;
438 }
439
440 FileId* getFileId(android::dataloader::Inode ino) {
441 auto it = mNodeToMetaMap.find(ino);
442 if (it != mNodeToMetaMap.end()) {
443 return &it->second.fileId;
444 }
445
446 auto* metaPair = updateMapsForFile(ino);
447 if (!metaPair) {
448 return nullptr;
449 }
450
451 return &metaPair->fileId;
452 }
453
454 void traceOrLogRead(const TracedRead& read, bool trace, bool log) {
455 if (!read.count) {
456 return;
457 }
458 if (trace) {
459 auto* meta = getMeta(read.fileIno);
460 auto str = android::base::StringPrintf(
461 "page_read: index=%lld count=%lld meta=%.*s",
462 static_cast<long long>(read.firstBlockIdx),
463 static_cast<long long>(read.count),
464 meta ? int(meta->size()) : 0, meta ? meta->data() : "");
465 ATRACE_BEGIN(str.c_str());
466 ATRACE_END();
467 }
468 if (log) {
469 mReadLog.reserve(ReadLogBufferSize);
470
471 auto fileId = getFileId(read.fileIno);
472 android::base::StringAppendF(
473 &mReadLog, "%lld:%lld:%lld:%lld\n",
474 static_cast<long long>(read.timestampUs),
475 static_cast<long long>(fileId ? *fileId : -1),
476 static_cast<long long>(read.firstBlockIdx),
477 static_cast<long long>(read.count));
478
479 if (mReadLog.size() >= mReadLog.capacity() - ReadLogMaxEntrySize) {
480 flushReadLog();
481 }
482 }
483 }
484
485 void flushReadLog() {
486 if (mReadLog.empty() || mReadLogFd == -1) {
487 return;
488 }
489
490 android::base::WriteStringToFd(mReadLog, mReadLogFd);
491 mReadLog.clear();
492 }
493
494private:
495 android::dataloader::FilesystemConnectorPtr mIfs = nullptr;
496 android::dataloader::StatusListenerPtr mStatusListener = nullptr;
497 android::base::unique_fd mInFd;
498 android::base::unique_fd mOutFd;
499 android::base::unique_fd mEventFd;
500 android::base::unique_fd mReadLogFd;
501 std::string mReadLog;
502 std::thread mReceiverThread;
503 std::mutex mMapsMutex;
504 std::unordered_map<android::dataloader::Inode, MetaPair> mNodeToMetaMap GUARDED_BY(mMapsMutex);
505 std::unordered_map<FileId, android::dataloader::Inode> mIdToNodeMap GUARDED_BY(mMapsMutex);
506 /** Tracks which files have been requested */
507 std::unordered_set<FileId> mRequestedFiles;
508 std::atomic<bool> mStopReceiving = false;
509};
510
511} // namespace
512
513int JNI_OnLoad(JavaVM* jvm, void* /* reserved */) {
514 android::dataloader::DataLoader::initialize(
515 [](auto) { return std::make_unique<AdbDataLoader>(); });
516 return JNI_VERSION_1_6;
517}