1 /*
2 * Copyright (C) 2020 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 "PackageManagerShellCommandDataLoader-jni"
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/no_destructor.h>
22 #include <android-base/stringprintf.h>
23 #include <android-base/unique_fd.h>
24 #include <core_jni_helpers.h>
25 #include <cutils/multiuser.h>
26 #include <cutils/trace.h>
27 #include <endian.h>
28 #include <nativehelper/JNIHelp.h>
29 #include <sys/eventfd.h>
30 #include <sys/poll.h>
31
32 #include <charconv>
33 #include <chrono>
34 #include <span>
35 #include <string>
36 #include <thread>
37 #include <unordered_map>
38 #include <unordered_set>
39
40 #include "dataloader.h"
41
42 // #define VERBOSE_READ_LOGS
43
44 namespace android {
45
46 namespace {
47
48 using android::base::borrowed_fd;
49 using android::base::unique_fd;
50
51 using namespace std::literals;
52
53 using BlockSize = int16_t;
54 using FileIdx = int16_t;
55 using BlockIdx = int32_t;
56 using NumBlocks = int32_t;
57 using BlockType = int8_t;
58 using CompressionType = int8_t;
59 using RequestType = int16_t;
60 using MagicType = uint32_t;
61
62 static constexpr int BUFFER_SIZE = 256 * 1024;
63 static constexpr int BLOCKS_COUNT = BUFFER_SIZE / INCFS_DATA_FILE_BLOCK_SIZE;
64
65 static constexpr int COMMAND_SIZE = 4 + 2 + 2 + 4; // bytes
66 static constexpr int HEADER_SIZE = 2 + 1 + 1 + 4 + 2; // bytes
67 static constexpr std::string_view OKAY = "OKAY"sv;
68 static constexpr MagicType INCR = 0x52434e49; // BE INCR
69
70 static constexpr auto PollTimeoutMs = 5000;
71 static constexpr auto TraceTagCheckInterval = 1s;
72
73 static constexpr auto WaitOnEofMinInterval = 10ms;
74 static constexpr auto WaitOnEofMaxInterval = 1s;
75
76 struct JniIds {
77 jclass packageManagerShellCommandDataLoader;
78 jmethodID pmscdLookupShellCommand;
79 jmethodID pmscdGetStdIn;
80 jmethodID pmscdGetLocalFile;
81
JniIdsandroid::__anon9ef61c320110::JniIds82 JniIds(JNIEnv* env) {
83 packageManagerShellCommandDataLoader = (jclass)env->NewGlobalRef(
84 FindClassOrDie(env, "com/android/server/pm/PackageManagerShellCommandDataLoader"));
85 pmscdLookupShellCommand =
86 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader,
87 "lookupShellCommand",
88 "(Ljava/lang/String;)Landroid/os/ShellCommand;");
89 pmscdGetStdIn = GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader,
90 "getStdIn", "(Landroid/os/ShellCommand;)I");
91 pmscdGetLocalFile =
92 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader, "getLocalFile",
93 "(Landroid/os/ShellCommand;Ljava/lang/String;)I");
94 }
95 };
96
jniIds(JNIEnv * env)97 const JniIds& jniIds(JNIEnv* env) {
98 static const JniIds ids(env);
99 return ids;
100 }
101
102 struct BlockHeader {
103 FileIdx fileIdx = -1;
104 BlockType blockType = -1;
105 CompressionType compressionType = -1;
106 BlockIdx blockIdx = -1;
107 BlockSize blockSize = -1;
108 } __attribute__((packed));
109
110 static_assert(sizeof(BlockHeader) == HEADER_SIZE);
111
112 static constexpr RequestType EXIT = 0;
113 static constexpr RequestType BLOCK_MISSING = 1;
114 static constexpr RequestType PREFETCH = 2;
115
116 struct RequestCommand {
117 MagicType magic;
118 RequestType requestType;
119 FileIdx fileIdx;
120 BlockIdx blockIdx;
121 } __attribute__((packed));
122
123 static_assert(COMMAND_SIZE == sizeof(RequestCommand));
124
sendRequest(int fd,RequestType requestType,FileIdx fileIdx=-1,BlockIdx blockIdx=-1)125 static bool sendRequest(int fd, RequestType requestType, FileIdx fileIdx = -1,
126 BlockIdx blockIdx = -1) {
127 const RequestCommand command{.magic = INCR,
128 .requestType = static_cast<int16_t>(be16toh(requestType)),
129 .fileIdx = static_cast<int16_t>(be16toh(fileIdx)),
130 .blockIdx = static_cast<int32_t>(be32toh(blockIdx))};
131 return android::base::WriteFully(fd, &command, sizeof(command));
132 }
133
readChunk(int fd,std::vector<uint8_t> & data)134 static bool readChunk(int fd, std::vector<uint8_t>& data) {
135 int32_t size;
136 if (!android::base::ReadFully(fd, &size, sizeof(size))) {
137 return false;
138 }
139 size = int32_t(be32toh(size));
140 if (size <= 0) {
141 return false;
142 }
143 data.resize(size);
144 return android::base::ReadFully(fd, data.data(), data.size());
145 }
146
147 BlockHeader readHeader(std::span<uint8_t>& data);
148
readLEInt32(borrowed_fd fd)149 static inline int32_t readLEInt32(borrowed_fd fd) {
150 int32_t result;
151 ReadFully(fd, &result, sizeof(result));
152 result = int32_t(le32toh(result));
153 return result;
154 }
155
skipBytes(borrowed_fd fd,int * max_size)156 static inline bool skipBytes(borrowed_fd fd, int* max_size) {
157 int32_t size = std::min(readLEInt32(fd), *max_size);
158 if (size <= 0) {
159 return false;
160 }
161 *max_size -= size;
162 return (TEMP_FAILURE_RETRY(lseek64(fd.get(), size, SEEK_CUR)) >= 0);
163 }
164
skipIdSigHeaders(borrowed_fd fd)165 static inline int32_t skipIdSigHeaders(borrowed_fd fd) {
166 // version
167 auto version = readLEInt32(fd);
168 int max_size = INCFS_MAX_SIGNATURE_SIZE - sizeof(version);
169 // hashingInfo and signingInfo
170 if (!skipBytes(fd, &max_size) || !skipBytes(fd, &max_size)) {
171 return -1;
172 }
173 return readLEInt32(fd); // size of the verity tree
174 }
175
verityTreeSizeForFile(IncFsSize fileSize)176 static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) {
177 constexpr int SHA256_DIGEST_SIZE = 32;
178 constexpr int digest_size = SHA256_DIGEST_SIZE;
179 constexpr int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
180
181 IncFsSize total_tree_block_count = 0;
182
183 auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
184 auto hash_block_count = block_count;
185 for (auto i = 0; hash_block_count > 1; i++) {
186 hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
187 total_tree_block_count += hash_block_count;
188 }
189 return total_tree_block_count * INCFS_DATA_FILE_BLOCK_SIZE;
190 }
191
192 enum MetadataMode : int8_t {
193 STDIN = 0,
194 LOCAL_FILE = 1,
195 DATA_ONLY_STREAMING = 2,
196 STREAMING = 3,
197 };
198
199 struct InputDesc {
200 unique_fd fd;
201 IncFsSize size;
202 IncFsBlockKind kind = INCFS_BLOCK_KIND_DATA;
203 bool waitOnEof = false;
204 bool streaming = false;
205 MetadataMode mode = STDIN;
206 };
207 using InputDescs = std::vector<InputDesc>;
208
209 template <class T>
read(IncFsSpan & data)210 std::optional<T> read(IncFsSpan& data) {
211 if (data.size < (int32_t)sizeof(T)) {
212 return {};
213 }
214 T res;
215 memcpy(&res, data.data, sizeof(res));
216 data.data += sizeof(res);
217 data.size -= sizeof(res);
218 return res;
219 }
220
openLocalFile(JNIEnv * env,const JniIds & jni,jobject shellCommand,const std::string & path)221 static inline unique_fd openLocalFile(JNIEnv* env, const JniIds& jni, jobject shellCommand,
222 const std::string& path) {
223 if (shellCommand) {
224 return unique_fd{env->CallStaticIntMethod(jni.packageManagerShellCommandDataLoader,
225 jni.pmscdGetLocalFile, shellCommand,
226 env->NewStringUTF(path.c_str()))};
227 }
228 auto fd = unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC));
229 if (!fd.ok()) {
230 PLOG(ERROR) << "Failed to open file: " << path << ", error code: " << fd.get();
231 }
232 return fd;
233 }
234
openLocalFile(JNIEnv * env,const JniIds & jni,jobject shellCommand,IncFsSize size,const std::string & filePath)235 static inline InputDescs openLocalFile(JNIEnv* env, const JniIds& jni, jobject shellCommand,
236 IncFsSize size, const std::string& filePath) {
237 InputDescs result;
238 result.reserve(2);
239
240 const std::string idsigPath = filePath + ".idsig";
241
242 unique_fd idsigFd = openLocalFile(env, jni, shellCommand, idsigPath);
243 if (idsigFd.ok()) {
244 auto actualTreeSize = skipIdSigHeaders(idsigFd);
245 if (actualTreeSize < 0) {
246 ALOGE("Error reading .idsig file: wrong format.");
247 return {};
248 }
249 auto treeSize = verityTreeSizeForFile(size);
250 if (treeSize != actualTreeSize) {
251 ALOGE("Verity tree size mismatch: %d vs .idsig: %d.", int(treeSize),
252 int(actualTreeSize));
253 return {};
254 }
255 result.push_back(InputDesc{
256 .fd = std::move(idsigFd),
257 .size = treeSize,
258 .kind = INCFS_BLOCK_KIND_HASH,
259 });
260 }
261
262 unique_fd fileFd = openLocalFile(env, jni, shellCommand, filePath);
263 if (fileFd.ok()) {
264 result.push_back(InputDesc{
265 .fd = std::move(fileFd),
266 .size = size,
267 });
268 }
269
270 return result;
271 }
272
openInputs(JNIEnv * env,const JniIds & jni,jobject shellCommand,IncFsSize size,IncFsSpan metadata)273 static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shellCommand,
274 IncFsSize size, IncFsSpan metadata) {
275 auto mode = read<int8_t>(metadata).value_or(STDIN);
276 if (mode == LOCAL_FILE) {
277 // local file and possibly signature
278 auto dataSize = le32toh(read<int32_t>(metadata).value_or(0));
279 return openLocalFile(env, jni, shellCommand, size, std::string(metadata.data, dataSize));
280 }
281
282 if (!shellCommand) {
283 ALOGE("Missing shell command.");
284 return {};
285 }
286
287 unique_fd fd{env->CallStaticIntMethod(jni.packageManagerShellCommandDataLoader,
288 jni.pmscdGetStdIn, shellCommand)};
289 if (!fd.ok()) {
290 return {};
291 }
292
293 InputDescs result;
294 switch (mode) {
295 case STDIN: {
296 result.push_back(InputDesc{
297 .fd = std::move(fd),
298 .size = size,
299 .waitOnEof = true,
300 });
301 break;
302 }
303 case DATA_ONLY_STREAMING: {
304 // verity tree from stdin, rest is streaming
305 auto treeSize = verityTreeSizeForFile(size);
306 result.push_back(InputDesc{
307 .fd = std::move(fd),
308 .size = treeSize,
309 .kind = INCFS_BLOCK_KIND_HASH,
310 .waitOnEof = true,
311 .streaming = true,
312 .mode = DATA_ONLY_STREAMING,
313 });
314 break;
315 }
316 case STREAMING: {
317 result.push_back(InputDesc{
318 .fd = std::move(fd),
319 .size = 0,
320 .streaming = true,
321 .mode = STREAMING,
322 });
323 break;
324 }
325 }
326 return result;
327 }
328
329 class PMSCDataLoader;
330
331 struct OnTraceChanged {
332 OnTraceChanged();
~OnTraceChangedandroid::__anon9ef61c320110::OnTraceChanged333 ~OnTraceChanged() {
334 mRunning = false;
335 mChecker.join();
336 }
337
registerCallbackandroid::__anon9ef61c320110::OnTraceChanged338 void registerCallback(PMSCDataLoader* callback) {
339 std::unique_lock lock(mMutex);
340 mCallbacks.insert(callback);
341 }
342
unregisterCallbackandroid::__anon9ef61c320110::OnTraceChanged343 void unregisterCallback(PMSCDataLoader* callback) {
344 std::unique_lock lock(mMutex);
345 mCallbacks.erase(callback);
346 }
347
348 private:
349 std::mutex mMutex;
350 std::unordered_set<PMSCDataLoader*> mCallbacks;
351 std::atomic<bool> mRunning{true};
352 std::thread mChecker;
353 };
354
onTraceChanged()355 static OnTraceChanged& onTraceChanged() {
356 static android::base::NoDestructor<OnTraceChanged> instance;
357 return *instance;
358 }
359
360 class PMSCDataLoader : public android::dataloader::DataLoader {
361 public:
PMSCDataLoader(JavaVM * jvm)362 PMSCDataLoader(JavaVM* jvm) : mJvm(jvm) { CHECK(mJvm); }
~PMSCDataLoader()363 ~PMSCDataLoader() {
364 onTraceChanged().unregisterCallback(this);
365 if (mReceiverThread.joinable()) {
366 mReceiverThread.join();
367 }
368 }
369
updateReadLogsState(const bool enabled)370 void updateReadLogsState(const bool enabled) {
371 if (enabled != mReadLogsEnabled.exchange(enabled)) {
372 mIfs->setParams({.readLogsEnabled = enabled});
373 }
374 }
375
376 private:
377 // Bitmask of supported features.
getFeatures() const378 DataLoaderFeatures getFeatures() const final { return DATA_LOADER_FEATURE_UID; }
379
380 // Lifecycle.
onCreate(const android::dataloader::DataLoaderParams & params,android::dataloader::FilesystemConnectorPtr ifs,android::dataloader::StatusListenerPtr statusListener,android::dataloader::ServiceConnectorPtr,android::dataloader::ServiceParamsPtr)381 bool onCreate(const android::dataloader::DataLoaderParams& params,
382 android::dataloader::FilesystemConnectorPtr ifs,
383 android::dataloader::StatusListenerPtr statusListener,
384 android::dataloader::ServiceConnectorPtr,
385 android::dataloader::ServiceParamsPtr) final {
386 CHECK(ifs) << "ifs can't be null";
387 CHECK(statusListener) << "statusListener can't be null";
388 mArgs = params.arguments();
389 mIfs = ifs;
390 mStatusListener = statusListener;
391 updateReadLogsState(atrace_is_tag_enabled(ATRACE_TAG));
392 onTraceChanged().registerCallback(this);
393 return true;
394 }
onStart()395 bool onStart() final { return true; }
onStop()396 void onStop() final {
397 mStopReceiving = true;
398 eventfd_write(mEventFd, 1);
399 if (mReceiverThread.joinable()) {
400 mReceiverThread.join();
401 }
402 }
onDestroy()403 void onDestroy() final {}
404
405 // Installation.
onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles)406 bool onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles) final {
407 ALOGE("onPrepareImage: start.");
408
409 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm, JNI_VERSION_1_6);
410 const auto& jni = jniIds(env);
411
412 jobject shellCommand = env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
413 jni.pmscdLookupShellCommand,
414 env->NewStringUTF(mArgs.c_str()));
415
416 std::vector<char> buffer;
417 buffer.reserve(BUFFER_SIZE);
418
419 std::vector<IncFsDataBlock> blocks;
420 blocks.reserve(BLOCKS_COUNT);
421
422 unique_fd streamingFd;
423 MetadataMode streamingMode;
424 for (auto&& file : addedFiles) {
425 auto inputs = openInputs(env, jni, shellCommand, file.size, file.metadata);
426 if (inputs.empty()) {
427 ALOGE("Failed to open an input file for metadata: %.*s, final file name is: %s. "
428 "Error %d",
429 int(file.metadata.size), file.metadata.data, file.name, errno);
430 return false;
431 }
432
433 const auto fileId = IncFs_FileIdFromMetadata(file.metadata);
434 const base::unique_fd incfsFd(mIfs->openForSpecialOps(fileId).release());
435 if (incfsFd < 0) {
436 ALOGE("Failed to open an IncFS file for metadata: %.*s, final file name is: %s. "
437 "Error %d",
438 int(file.metadata.size), file.metadata.data, file.name, errno);
439 return false;
440 }
441
442 for (auto&& input : inputs) {
443 if (input.streaming && !streamingFd.ok()) {
444 streamingFd.reset(dup(input.fd));
445 streamingMode = input.mode;
446 }
447 if (!copyToIncFs(incfsFd, input.size, input.kind, input.fd, input.waitOnEof,
448 &buffer, &blocks)) {
449 ALOGE("Failed to copy data to IncFS file for metadata: %.*s, final file name "
450 "is: %s. "
451 "Error %d",
452 int(file.metadata.size), file.metadata.data, file.name, errno);
453 return false;
454 }
455 }
456 }
457
458 if (streamingFd.ok()) {
459 ALOGE("onPrepareImage: done, proceeding to streaming.");
460 return initStreaming(std::move(streamingFd), streamingMode);
461 }
462
463 ALOGE("onPrepareImage: done.");
464 return true;
465 }
466
copyToIncFs(borrowed_fd incfsFd,IncFsSize size,IncFsBlockKind kind,borrowed_fd incomingFd,bool waitOnEof,std::vector<char> * buffer,std::vector<IncFsDataBlock> * blocks)467 bool copyToIncFs(borrowed_fd incfsFd, IncFsSize size, IncFsBlockKind kind,
468 borrowed_fd incomingFd, bool waitOnEof, std::vector<char>* buffer,
469 std::vector<IncFsDataBlock>* blocks) {
470 IncFsSize remaining = size;
471 IncFsSize totalSize = 0;
472 IncFsBlockIndex blockIdx = 0;
473 while (remaining > 0) {
474 constexpr auto capacity = BUFFER_SIZE;
475 auto size = buffer->size();
476 if (capacity - size < INCFS_DATA_FILE_BLOCK_SIZE) {
477 if (!flashToIncFs(incfsFd, kind, false, &blockIdx, buffer, blocks)) {
478 return false;
479 }
480 continue;
481 }
482
483 auto toRead = std::min<IncFsSize>(remaining, capacity - size);
484 buffer->resize(size + toRead);
485 auto read = ::read(incomingFd.get(), buffer->data() + size, toRead);
486 if (read == 0) {
487 if (waitOnEof) {
488 // eof of stdin, waiting...
489 if (doWaitOnEof()) {
490 continue;
491 } else {
492 return false;
493 }
494 }
495 break;
496 }
497 resetWaitOnEof();
498
499 if (read < 0) {
500 return false;
501 }
502
503 buffer->resize(size + read);
504 remaining -= read;
505 totalSize += read;
506 }
507 if (!buffer->empty() && !flashToIncFs(incfsFd, kind, true, &blockIdx, buffer, blocks)) {
508 return false;
509 }
510 return true;
511 }
512
flashToIncFs(borrowed_fd incfsFd,IncFsBlockKind kind,bool eof,IncFsBlockIndex * blockIdx,std::vector<char> * buffer,std::vector<IncFsDataBlock> * blocks)513 bool flashToIncFs(borrowed_fd incfsFd, IncFsBlockKind kind, bool eof, IncFsBlockIndex* blockIdx,
514 std::vector<char>* buffer, std::vector<IncFsDataBlock>* blocks) {
515 int consumed = 0;
516 const auto fullBlocks = buffer->size() / INCFS_DATA_FILE_BLOCK_SIZE;
517 for (int i = 0; i < fullBlocks; ++i) {
518 const auto inst = IncFsDataBlock{
519 .fileFd = incfsFd.get(),
520 .pageIndex = (*blockIdx)++,
521 .compression = INCFS_COMPRESSION_KIND_NONE,
522 .kind = kind,
523 .dataSize = INCFS_DATA_FILE_BLOCK_SIZE,
524 .data = buffer->data() + consumed,
525 };
526 blocks->push_back(inst);
527 consumed += INCFS_DATA_FILE_BLOCK_SIZE;
528 }
529 const auto remain = buffer->size() - fullBlocks * INCFS_DATA_FILE_BLOCK_SIZE;
530 if (remain && eof) {
531 const auto inst = IncFsDataBlock{
532 .fileFd = incfsFd.get(),
533 .pageIndex = (*blockIdx)++,
534 .compression = INCFS_COMPRESSION_KIND_NONE,
535 .kind = kind,
536 .dataSize = static_cast<uint16_t>(remain),
537 .data = buffer->data() + consumed,
538 };
539 blocks->push_back(inst);
540 consumed += remain;
541 }
542
543 auto res = mIfs->writeBlocks({blocks->data(), blocks->size()});
544
545 blocks->clear();
546 buffer->erase(buffer->begin(), buffer->begin() + consumed);
547
548 if (res < 0) {
549 ALOGE("Failed to write block to IncFS: %d", int(res));
550 return false;
551 }
552 return true;
553 }
554
555 enum class WaitResult {
556 DataAvailable,
557 Timeout,
558 Failure,
559 StopRequested,
560 };
561
waitForData(int fd)562 WaitResult waitForData(int fd) {
563 using Clock = std::chrono::steady_clock;
564 using Milliseconds = std::chrono::milliseconds;
565
566 auto pollTimeoutMs = PollTimeoutMs;
567 const auto waitEnd = Clock::now() + Milliseconds(pollTimeoutMs);
568 while (!mStopReceiving) {
569 struct pollfd pfds[2] = {{fd, POLLIN, 0}, {mEventFd, POLLIN, 0}};
570 // Wait until either data is ready or stop signal is received
571 int res = poll(pfds, std::size(pfds), pollTimeoutMs);
572
573 if (res < 0) {
574 if (errno == EINTR) {
575 pollTimeoutMs = std::chrono::duration_cast<Milliseconds>(waitEnd - Clock::now())
576 .count();
577 if (pollTimeoutMs < 0) {
578 return WaitResult::Timeout;
579 }
580 continue;
581 }
582 ALOGE("Failed to poll. Error %d", errno);
583 return WaitResult::Failure;
584 }
585
586 if (res == 0) {
587 return WaitResult::Timeout;
588 }
589
590 // First check if there is a stop signal
591 if (pfds[1].revents == POLLIN) {
592 ALOGE("DataLoader requested to stop.");
593 return WaitResult::StopRequested;
594 }
595 // Otherwise check if incoming data is ready
596 if (pfds[0].revents == POLLIN) {
597 return WaitResult::DataAvailable;
598 }
599
600 // Invalid case, just fail.
601 ALOGE("Failed to poll. Result %d", res);
602 return WaitResult::Failure;
603 }
604
605 ALOGE("DataLoader requested to stop.");
606 return WaitResult::StopRequested;
607 }
608
609 // Streaming.
initStreaming(unique_fd inout,MetadataMode mode)610 bool initStreaming(unique_fd inout, MetadataMode mode) {
611 mEventFd.reset(eventfd(0, EFD_CLOEXEC));
612 if (mEventFd < 0) {
613 ALOGE("Failed to create eventfd.");
614 return false;
615 }
616
617 // Awaiting adb handshake.
618 if (waitForData(inout) != WaitResult::DataAvailable) {
619 ALOGE("Failure waiting for the handshake.");
620 return false;
621 }
622
623 char okay_buf[OKAY.size()];
624 if (!android::base::ReadFully(inout, okay_buf, OKAY.size())) {
625 ALOGE("Failed to receive OKAY. Abort. Error %d", errno);
626 return false;
627 }
628 if (std::string_view(okay_buf, OKAY.size()) != OKAY) {
629 ALOGE("Received '%.*s', expecting '%.*s'", (int)OKAY.size(), okay_buf, (int)OKAY.size(),
630 OKAY.data());
631 return false;
632 }
633
634 {
635 std::lock_guard lock{mOutFdLock};
636 mOutFd.reset(::dup(inout));
637 if (mOutFd < 0) {
638 ALOGE("Failed to create streaming fd.");
639 }
640 }
641
642 if (mStopReceiving) {
643 ALOGE("DataLoader requested to stop.");
644 return false;
645 }
646
647 mReceiverThread = std::thread(
648 [this, io = std::move(inout), mode]() mutable { receiver(std::move(io), mode); });
649
650 ALOGI("Started streaming...");
651 return true;
652 }
653
654 // IFS callbacks.
onPendingReads(dataloader::PendingReads pendingReads)655 void onPendingReads(dataloader::PendingReads pendingReads) final {}
onPageReads(dataloader::PageReads pageReads)656 void onPageReads(dataloader::PageReads pageReads) final {}
657
onPendingReadsWithUid(dataloader::PendingReadsWithUid pendingReads)658 void onPendingReadsWithUid(dataloader::PendingReadsWithUid pendingReads) final {
659 std::lock_guard lock{mOutFdLock};
660 if (mOutFd < 0) {
661 return;
662 }
663 CHECK(mIfs);
664 for (auto&& pendingRead : pendingReads) {
665 const android::dataloader::FileId& fileId = pendingRead.id;
666 const auto blockIdx = static_cast<BlockIdx>(pendingRead.block);
667 /*
668 ALOGI("Missing: %d", (int) blockIdx);
669 */
670 FileIdx fileIdx = convertFileIdToFileIndex(fileId);
671 if (fileIdx < 0) {
672 ALOGE("Failed to handle event for fileid=%s. Ignore.",
673 android::incfs::toString(fileId).c_str());
674 continue;
675 }
676 if (mRequestedFiles.insert(fileIdx).second &&
677 !sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
678 mRequestedFiles.erase(fileIdx);
679 }
680 sendRequest(mOutFd, BLOCK_MISSING, fileIdx, blockIdx);
681 }
682 }
683
684 // Read tracing.
685 struct TracedRead {
686 uint64_t timestampUs;
687 android::dataloader::FileId fileId;
688 android::dataloader::Uid uid;
689 uint32_t firstBlockIdx;
690 uint32_t count;
691 };
692
onPageReadsWithUid(dataloader::PageReadsWithUid pageReads)693 void onPageReadsWithUid(dataloader::PageReadsWithUid pageReads) final {
694 if (!pageReads.size()) {
695 return;
696 }
697
698 auto trace = atrace_is_tag_enabled(ATRACE_TAG);
699 if (CC_LIKELY(!trace)) {
700 return;
701 }
702
703 TracedRead last = {};
704 auto lastSerialNo = mLastSerialNo < 0 ? pageReads[0].serialNo : mLastSerialNo;
705 for (auto&& read : pageReads) {
706 const auto expectedSerialNo = lastSerialNo + last.count;
707 #ifdef VERBOSE_READ_LOGS
708 {
709 FileIdx fileIdx = convertFileIdToFileIndex(read.id);
710
711 auto appId = multiuser_get_app_id(read.uid);
712 auto userId = multiuser_get_user_id(read.uid);
713 auto trace = android::base::
714 StringPrintf("verbose_page_read: serialNo=%lld (expected=%lld) index=%lld "
715 "file=%d appid=%d userid=%d",
716 static_cast<long long>(read.serialNo),
717 static_cast<long long>(expectedSerialNo),
718 static_cast<long long>(read.block), static_cast<int>(fileIdx),
719 static_cast<int>(appId), static_cast<int>(userId));
720
721 ATRACE_BEGIN(trace.c_str());
722 ATRACE_END();
723 }
724 #endif // VERBOSE_READ_LOGS
725
726 if (read.serialNo == expectedSerialNo && read.id == last.fileId &&
727 read.uid == last.uid && read.block == last.firstBlockIdx + last.count) {
728 ++last.count;
729 continue;
730 }
731
732 // First, trace the reads.
733 traceRead(last);
734
735 // Second, report missing reads, if any.
736 if (read.serialNo != expectedSerialNo) {
737 traceMissingReads(expectedSerialNo, read.serialNo);
738 }
739
740 last = TracedRead{
741 .timestampUs = read.bootClockTsUs,
742 .fileId = read.id,
743 .uid = read.uid,
744 .firstBlockIdx = (uint32_t)read.block,
745 .count = 1,
746 };
747 lastSerialNo = read.serialNo;
748 }
749
750 traceRead(last);
751 mLastSerialNo = lastSerialNo + last.count;
752 }
753
traceRead(const TracedRead & read)754 void traceRead(const TracedRead& read) {
755 if (!read.count) {
756 return;
757 }
758
759 FileIdx fileIdx = convertFileIdToFileIndex(read.fileId);
760
761 std::string trace;
762 if (read.uid != kIncFsNoUid) {
763 auto appId = multiuser_get_app_id(read.uid);
764 auto userId = multiuser_get_user_id(read.uid);
765 trace = android::base::
766 StringPrintf("page_read: index=%lld count=%lld file=%d appid=%d userid=%d",
767 static_cast<long long>(read.firstBlockIdx),
768 static_cast<long long>(read.count), static_cast<int>(fileIdx),
769 static_cast<int>(appId), static_cast<int>(userId));
770 } else {
771 trace = android::base::StringPrintf("page_read: index=%lld count=%lld file=%d",
772 static_cast<long long>(read.firstBlockIdx),
773 static_cast<long long>(read.count),
774 static_cast<int>(fileIdx));
775 }
776
777 ATRACE_BEGIN(trace.c_str());
778 ATRACE_END();
779 }
780
traceMissingReads(int64_t expectedSerialNo,int64_t readSerialNo)781 void traceMissingReads(int64_t expectedSerialNo, int64_t readSerialNo) {
782 const auto readsMissing = readSerialNo - expectedSerialNo;
783 const auto trace =
784 android::base::StringPrintf("missing_page_reads: count=%lld, range [%lld,%lld)",
785 static_cast<long long>(readsMissing),
786 static_cast<long long>(expectedSerialNo),
787 static_cast<long long>(readSerialNo));
788 ATRACE_BEGIN(trace.c_str());
789 ATRACE_END();
790 }
791
receiver(unique_fd inout,MetadataMode mode)792 void receiver(unique_fd inout, MetadataMode mode) {
793 std::vector<uint8_t> data;
794 std::vector<IncFsDataBlock> instructions;
795 std::unordered_map<FileIdx, unique_fd> writeFds;
796 while (!mStopReceiving) {
797 const auto res = waitForData(inout);
798 if (res == WaitResult::Timeout) {
799 continue;
800 }
801 if (res == WaitResult::Failure) {
802 mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
803 break;
804 }
805 if (res == WaitResult::StopRequested) {
806 ALOGE("Sending EXIT to server.");
807 sendRequest(inout, EXIT);
808 break;
809 }
810 if (!readChunk(inout, data)) {
811 ALOGE("Failed to read a message. Abort.");
812 mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
813 break;
814 }
815 auto remainingData = std::span(data);
816 while (!remainingData.empty()) {
817 auto header = readHeader(remainingData);
818 if (header.fileIdx == -1 && header.blockType == 0 && header.compressionType == 0 &&
819 header.blockIdx == 0 && header.blockSize == 0) {
820 ALOGI("Stop command received. Sending exit command (remaining bytes: %d).",
821 int(remainingData.size()));
822
823 sendRequest(inout, EXIT);
824 mStopReceiving = true;
825 break;
826 }
827 if (header.fileIdx < 0 || header.blockSize <= 0 || header.blockType < 0 ||
828 header.compressionType < 0 || header.blockIdx < 0) {
829 ALOGE("Invalid header received. Abort.");
830 mStopReceiving = true;
831 break;
832 }
833
834 const FileIdx fileIdx = header.fileIdx;
835 const android::dataloader::FileId fileId = convertFileIndexToFileId(mode, fileIdx);
836 if (!android::incfs::isValidFileId(fileId)) {
837 ALOGE("Unknown data destination for file ID %d. Ignore.", header.fileIdx);
838 continue;
839 }
840
841 auto& writeFd = writeFds[fileIdx];
842 if (writeFd < 0) {
843 writeFd.reset(this->mIfs->openForSpecialOps(fileId).release());
844 if (writeFd < 0) {
845 ALOGE("Failed to open file %d for writing (%d). Abort.", header.fileIdx,
846 -writeFd);
847 break;
848 }
849 }
850
851 const auto inst = IncFsDataBlock{
852 .fileFd = writeFd,
853 .pageIndex = static_cast<IncFsBlockIndex>(header.blockIdx),
854 .compression = static_cast<IncFsCompressionKind>(header.compressionType),
855 .kind = static_cast<IncFsBlockKind>(header.blockType),
856 .dataSize = static_cast<uint16_t>(header.blockSize),
857 .data = (const char*)remainingData.data(),
858 };
859 instructions.push_back(inst);
860 remainingData = remainingData.subspan(header.blockSize);
861 }
862 writeInstructions(instructions);
863 }
864 writeInstructions(instructions);
865
866 {
867 std::lock_guard lock{mOutFdLock};
868 mOutFd.reset();
869 }
870 }
871
writeInstructions(std::vector<IncFsDataBlock> & instructions)872 void writeInstructions(std::vector<IncFsDataBlock>& instructions) {
873 auto res = this->mIfs->writeBlocks(instructions);
874 if (res != instructions.size()) {
875 ALOGE("Dailed to write data to Incfs (res=%d when expecting %d)", res,
876 int(instructions.size()));
877 }
878 instructions.clear();
879 }
880
convertFileIdToFileIndex(android::dataloader::FileId fileId)881 FileIdx convertFileIdToFileIndex(android::dataloader::FileId fileId) {
882 // FileId has format '\2FileIdx'.
883 const char* meta = (const char*)&fileId;
884
885 int8_t mode = *meta;
886 if (mode != DATA_ONLY_STREAMING && mode != STREAMING) {
887 return -1;
888 }
889
890 int fileIdx;
891 auto res = std::from_chars(meta + 1, meta + sizeof(fileId), fileIdx);
892 if (res.ec != std::errc{} || fileIdx < std::numeric_limits<FileIdx>::min() ||
893 fileIdx > std::numeric_limits<FileIdx>::max()) {
894 return -1;
895 }
896
897 return FileIdx(fileIdx);
898 }
899
convertFileIndexToFileId(MetadataMode mode,FileIdx fileIdx)900 android::dataloader::FileId convertFileIndexToFileId(MetadataMode mode, FileIdx fileIdx) {
901 IncFsFileId fileId = {};
902 char* meta = (char*)&fileId;
903 *meta = mode;
904 if (auto [p, ec] = std::to_chars(meta + 1, meta + sizeof(fileId), fileIdx);
905 ec != std::errc()) {
906 return {};
907 }
908 return fileId;
909 }
910
911 // Waiting with exponential backoff, maximum total time ~1.2sec.
doWaitOnEof()912 bool doWaitOnEof() {
913 if (mWaitOnEofInterval >= WaitOnEofMaxInterval) {
914 resetWaitOnEof();
915 return false;
916 }
917 auto result = mWaitOnEofInterval;
918 mWaitOnEofInterval =
919 std::min<std::chrono::milliseconds>(mWaitOnEofInterval * 2, WaitOnEofMaxInterval);
920 std::this_thread::sleep_for(result);
921 return true;
922 }
923
resetWaitOnEof()924 void resetWaitOnEof() { mWaitOnEofInterval = WaitOnEofMinInterval; }
925
926 JavaVM* const mJvm;
927 std::string mArgs;
928 android::dataloader::FilesystemConnectorPtr mIfs = nullptr;
929 android::dataloader::StatusListenerPtr mStatusListener = nullptr;
930 std::mutex mOutFdLock;
931 android::base::unique_fd mOutFd;
932 android::base::unique_fd mEventFd;
933 std::thread mReceiverThread;
934 std::atomic<bool> mStopReceiving = false;
935 std::atomic<bool> mReadLogsEnabled = false;
936 std::chrono::milliseconds mWaitOnEofInterval{WaitOnEofMinInterval};
937 int64_t mLastSerialNo{-1};
938 /** Tracks which files have been requested */
939 std::unordered_set<FileIdx> mRequestedFiles;
940 };
941
OnTraceChanged()942 OnTraceChanged::OnTraceChanged() {
943 mChecker = std::thread([this]() {
944 bool oldTrace = atrace_is_tag_enabled(ATRACE_TAG);
945 while (mRunning) {
946 bool newTrace = atrace_is_tag_enabled(ATRACE_TAG);
947 if (oldTrace != newTrace) {
948 std::unique_lock lock(mMutex);
949 for (auto&& callback : mCallbacks) {
950 callback->updateReadLogsState(newTrace);
951 }
952 }
953 oldTrace = newTrace;
954 std::this_thread::sleep_for(TraceTagCheckInterval);
955 }
956 });
957 }
958
readHeader(std::span<uint8_t> & data)959 BlockHeader readHeader(std::span<uint8_t>& data) {
960 BlockHeader header;
961 if (data.size() < sizeof(header)) {
962 return header;
963 }
964
965 header.fileIdx = static_cast<FileIdx>(be16toh(*reinterpret_cast<const uint16_t*>(&data[0])));
966 header.blockType = static_cast<BlockType>(data[2]);
967 header.compressionType = static_cast<CompressionType>(data[3]);
968 header.blockIdx = static_cast<BlockIdx>(be32toh(*reinterpret_cast<const uint32_t*>(&data[4])));
969 header.blockSize =
970 static_cast<BlockSize>(be16toh(*reinterpret_cast<const uint16_t*>(&data[8])));
971 data = data.subspan(sizeof(header));
972
973 return header;
974 }
975
nativeInitialize(JNIEnv * env,jclass klass)976 static void nativeInitialize(JNIEnv* env, jclass klass) {
977 jniIds(env);
978 }
979
980 static const JNINativeMethod method_table[] = {
981 {"nativeInitialize", "()V", (void*)nativeInitialize},
982 };
983
984 } // namespace
985
register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv * env)986 int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(
987 JNIEnv* env) {
988 android::dataloader::DataLoader::initialize(
989 [](auto jvm, const auto& params) -> android::dataloader::DataLoaderPtr {
990 if (params.type() == DATA_LOADER_TYPE_INCREMENTAL) {
991 // This DataLoader only supports incremental installations.
992 return std::make_unique<PMSCDataLoader>(jvm);
993 }
994 return {};
995 });
996 return jniRegisterNativeMethods(env,
997 "com/android/server/pm/PackageManagerShellCommandDataLoader",
998 method_table, NELEM(method_table));
999 }
1000
1001 } // namespace android
1002