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