blob: e9a5e58e49d1ba96a7671d94bfbfce2f18055983 [file] [log] [blame]
Alex Buynytskyy04f73912020-02-10 08:34:18 -08001/*
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"
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080019#include <android-base/file.h>
Songchun Fanb8ab0032020-02-26 11:02:37 -080020#include <android-base/logging.h>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080021#include <android-base/stringprintf.h>
Alex Buynytskyy04f73912020-02-10 08:34:18 -080022#include <android-base/unique_fd.h>
Songchun Fanb8ab0032020-02-26 11:02:37 -080023#include <core_jni_helpers.h>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080024#include <cutils/trace.h>
Songchun Fanb8ab0032020-02-26 11:02:37 -080025#include <endian.h>
26#include <nativehelper/JNIHelp.h>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080027#include <sys/eventfd.h>
28#include <sys/poll.h>
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -080029
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080030#include <charconv>
Alex Buynytskyy04f73912020-02-10 08:34:18 -080031#include <chrono>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080032#include <span>
33#include <string>
Alex Buynytskyy04f73912020-02-10 08:34:18 -080034#include <thread>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080035#include <unordered_map>
36#include <unordered_set>
Alex Buynytskyy04f73912020-02-10 08:34:18 -080037
Songchun Fanb8ab0032020-02-26 11:02:37 -080038#include "dataloader.h"
39
Alex Buynytskyy04f73912020-02-10 08:34:18 -080040namespace android {
41
42namespace {
43
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -080044using android::base::borrowed_fd;
45using android::base::ReadFully;
Alex Buynytskyy04f73912020-02-10 08:34:18 -080046using android::base::unique_fd;
47
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080048using namespace std::literals;
49
50using BlockSize = int16_t;
51using FileIdx = int16_t;
52using BlockIdx = int32_t;
53using NumBlocks = int32_t;
Alex Buynytskyye9d20f02020-03-20 10:45:51 -070054using BlockType = int8_t;
55using CompressionType = int8_t;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080056using RequestType = int16_t;
57using MagicType = uint32_t;
58
Alex Buynytskyy04f73912020-02-10 08:34:18 -080059static constexpr int BUFFER_SIZE = 256 * 1024;
60static constexpr int BLOCKS_COUNT = BUFFER_SIZE / INCFS_DATA_FILE_BLOCK_SIZE;
61
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080062static constexpr int COMMAND_SIZE = 4 + 2 + 2 + 4; // bytes
Alex Buynytskyye9d20f02020-03-20 10:45:51 -070063static constexpr int HEADER_SIZE = 2 + 1 + 1 + 4 + 2; // bytes
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080064static constexpr std::string_view OKAY = "OKAY"sv;
65static constexpr MagicType INCR = 0x52434e49; // BE INCR
66
67static constexpr auto PollTimeoutMs = 5000;
68
Alex Buynytskyy04f73912020-02-10 08:34:18 -080069struct JniIds {
70 jclass packageManagerShellCommandDataLoader;
71 jmethodID pmscdLookupShellCommand;
72 jmethodID pmscdGetStdInPFD;
73 jmethodID pmscdGetLocalFile;
74
75 jmethodID parcelFileDescriptorGetFileDescriptor;
76
77 jclass ioUtils;
78 jmethodID ioUtilsCloseQuietly;
79
80 JniIds(JNIEnv* env) {
81 packageManagerShellCommandDataLoader = (jclass)env->NewGlobalRef(
82 FindClassOrDie(env, "com/android/server/pm/PackageManagerShellCommandDataLoader"));
83 pmscdLookupShellCommand =
84 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader,
85 "lookupShellCommand",
86 "(Ljava/lang/String;)Landroid/os/ShellCommand;");
87 pmscdGetStdInPFD =
88 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader, "getStdInPFD",
89 "(Landroid/os/ShellCommand;)Landroid/os/"
90 "ParcelFileDescriptor;");
91 pmscdGetLocalFile =
92 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader, "getLocalFile",
93 "(Landroid/os/ShellCommand;Ljava/lang/String;)Landroid/os/"
94 "ParcelFileDescriptor;");
95
96 auto parcelFileDescriptor = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
97 parcelFileDescriptorGetFileDescriptor =
98 GetMethodIDOrDie(env, parcelFileDescriptor, "getFileDescriptor",
99 "()Ljava/io/FileDescriptor;");
100
101 ioUtils = (jclass)env->NewGlobalRef(FindClassOrDie(env, "libcore/io/IoUtils"));
102 ioUtilsCloseQuietly = GetStaticMethodIDOrDie(env, ioUtils, "closeQuietly",
103 "(Ljava/lang/AutoCloseable;)V");
104 }
105};
106
107const JniIds& jniIds(JNIEnv* env) {
108 static const JniIds ids(env);
109 return ids;
110}
111
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800112struct BlockHeader {
113 FileIdx fileIdx = -1;
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700114 BlockType blockType = -1;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800115 CompressionType compressionType = -1;
116 BlockIdx blockIdx = -1;
117 BlockSize blockSize = -1;
118} __attribute__((packed));
119
120static_assert(sizeof(BlockHeader) == HEADER_SIZE);
121
122static constexpr RequestType EXIT = 0;
123static constexpr RequestType BLOCK_MISSING = 1;
124static constexpr RequestType PREFETCH = 2;
125
126struct RequestCommand {
127 MagicType magic;
128 RequestType requestType;
129 FileIdx fileIdx;
130 BlockIdx blockIdx;
131} __attribute__((packed));
132
133static_assert(COMMAND_SIZE == sizeof(RequestCommand));
134
135static bool sendRequest(int fd, RequestType requestType, FileIdx fileIdx = -1,
136 BlockIdx blockIdx = -1) {
137 const RequestCommand command{.magic = INCR,
138 .requestType = static_cast<int16_t>(be16toh(requestType)),
139 .fileIdx = static_cast<int16_t>(be16toh(fileIdx)),
140 .blockIdx = static_cast<int32_t>(be32toh(blockIdx))};
141 return android::base::WriteFully(fd, &command, sizeof(command));
142}
143
144static int waitForDataOrSignal(int fd, int event_fd) {
145 struct pollfd pfds[2] = {{fd, POLLIN, 0}, {event_fd, POLLIN, 0}};
146 // Wait indefinitely until either data is ready or stop signal is received
147 int res = poll(pfds, 2, PollTimeoutMs);
148 if (res <= 0) {
149 return res;
150 }
151 // First check if there is a stop signal
152 if (pfds[1].revents == POLLIN) {
153 return event_fd;
154 }
155 // Otherwise check if incoming data is ready
156 if (pfds[0].revents == POLLIN) {
157 return fd;
158 }
159 return -1;
160}
161
162static bool readChunk(int fd, std::vector<uint8_t>& data) {
163 int32_t size;
164 if (!android::base::ReadFully(fd, &size, sizeof(size))) {
165 return false;
166 }
167 size = int32_t(be32toh(size));
168 if (size <= 0) {
169 return false;
170 }
171 data.resize(size);
172 return android::base::ReadFully(fd, data.data(), data.size());
173}
174
175BlockHeader readHeader(std::span<uint8_t>& data);
176
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700177static inline int32_t readLEInt32(borrowed_fd fd) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800178 int32_t result;
179 ReadFully(fd, &result, sizeof(result));
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700180 result = int32_t(le32toh(result));
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800181 return result;
182}
183
184static inline std::vector<char> readBytes(borrowed_fd fd) {
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700185 int32_t size = readLEInt32(fd);
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800186 std::vector<char> result(size);
187 ReadFully(fd, result.data(), size);
188 return result;
189}
190
191static inline int32_t skipIdSigHeaders(borrowed_fd fd) {
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700192 readLEInt32(fd); // version
193 readBytes(fd); // hashingInfo
194 readBytes(fd); // signingInfo
195 return readLEInt32(fd); // size of the verity tree
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800196}
197
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800198static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) {
199 constexpr int SHA256_DIGEST_SIZE = 32;
200 constexpr int digest_size = SHA256_DIGEST_SIZE;
201 constexpr int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
202
203 IncFsSize total_tree_block_count = 0;
204
205 auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
206 auto hash_block_count = block_count;
207 for (auto i = 0; hash_block_count > 1; i++) {
208 hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
209 total_tree_block_count += hash_block_count;
210 }
211 return total_tree_block_count * INCFS_DATA_FILE_BLOCK_SIZE;
212}
213
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800214static inline unique_fd convertPfdToFdAndDup(JNIEnv* env, const JniIds& jni, jobject pfd) {
215 if (!pfd) {
216 ALOGE("Missing In ParcelFileDescriptor.");
217 return {};
218 }
219 auto managedFd = env->CallObjectMethod(pfd, jni.parcelFileDescriptorGetFileDescriptor);
220 if (!pfd) {
221 ALOGE("Missing In FileDescriptor.");
222 return {};
223 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800224 unique_fd result{dup(jniGetFDFromFileDescriptor(env, managedFd))};
225 // Can be closed after dup.
226 env->CallStaticVoidMethod(jni.ioUtils, jni.ioUtilsCloseQuietly, pfd);
227 return result;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800228}
229
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700230enum MetadataMode : int8_t {
231 STDIN = 0,
232 LOCAL_FILE = 1,
233 DATA_ONLY_STREAMING = 2,
234 STREAMING = 3,
235};
236
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800237struct InputDesc {
238 unique_fd fd;
239 IncFsSize size;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800240 IncFsBlockKind kind = INCFS_BLOCK_KIND_DATA;
241 bool waitOnEof = false;
242 bool streaming = false;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700243 MetadataMode mode = STDIN;
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800244};
245using InputDescs = std::vector<InputDesc>;
246
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700247template <class T>
248std::optional<T> read(IncFsSpan& data) {
249 if (data.size < (int32_t)sizeof(T)) {
250 return {};
251 }
252 T res;
253 memcpy(&res, data.data, sizeof(res));
254 data.data += sizeof(res);
255 data.size -= sizeof(res);
256 return res;
257}
258
259static inline InputDescs openLocalFile(JNIEnv* env, const JniIds& jni, jobject shellCommand,
260 IncFsSize size, const std::string& filePath) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800261 InputDescs result;
262 result.reserve(2);
263
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800264 const std::string idsigPath = filePath + ".idsig";
265
266 auto idsigFd = convertPfdToFdAndDup(
267 env, jni,
268 env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
269 jni.pmscdGetLocalFile, shellCommand,
270 env->NewStringUTF(idsigPath.c_str())));
271 if (idsigFd.ok()) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800272 auto treeSize = verityTreeSizeForFile(size);
273 auto actualTreeSize = skipIdSigHeaders(idsigFd);
274 if (treeSize != actualTreeSize) {
275 ALOGE("Verity tree size mismatch: %d vs .idsig: %d.", int(treeSize),
276 int(actualTreeSize));
277 return {};
278 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800279 result.push_back(InputDesc{
280 .fd = std::move(idsigFd),
281 .size = treeSize,
282 .kind = INCFS_BLOCK_KIND_HASH,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800283 });
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800284 }
285
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800286 auto fileFd = convertPfdToFdAndDup(
287 env, jni,
288 env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
289 jni.pmscdGetLocalFile, shellCommand,
290 env->NewStringUTF(filePath.c_str())));
291 if (fileFd.ok()) {
292 result.push_back(InputDesc{
293 .fd = std::move(fileFd),
294 .size = size,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800295 });
296 }
297
298 return result;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800299}
300
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700301static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shellCommand,
302 IncFsSize size, IncFsSpan metadata) {
303 auto mode = read<int8_t>(metadata).value_or(STDIN);
304 if (mode == LOCAL_FILE) {
305 // local file and possibly signature
306 return openLocalFile(env, jni, shellCommand, size,
307 std::string(metadata.data, metadata.size));
308 }
309
310 auto fd = convertPfdToFdAndDup(
311 env, jni,
312 env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
313 jni.pmscdGetStdInPFD, shellCommand));
314 if (!fd.ok()) {
315 return {};
316 }
317
318 InputDescs result;
319 switch (mode) {
320 case STDIN: {
321 result.push_back(InputDesc{
322 .fd = std::move(fd),
323 .size = size,
324 .waitOnEof = true,
325 });
326 break;
327 }
328 case DATA_ONLY_STREAMING: {
329 // verity tree from stdin, rest is streaming
330 auto treeSize = verityTreeSizeForFile(size);
331 result.push_back(InputDesc{
332 .fd = std::move(fd),
333 .size = treeSize,
334 .kind = INCFS_BLOCK_KIND_HASH,
335 .waitOnEof = true,
336 .streaming = true,
337 .mode = DATA_ONLY_STREAMING,
338 });
339 break;
340 }
341 case STREAMING: {
342 result.push_back(InputDesc{
343 .fd = std::move(fd),
344 .size = 0,
345 .streaming = true,
346 .mode = STREAMING,
347 });
348 break;
349 }
350 }
351 return result;
352}
353
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800354static inline JNIEnv* GetJNIEnvironment(JavaVM* vm) {
355 JNIEnv* env;
356 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
357 return 0;
358 }
359 return env;
360}
361
362static inline JNIEnv* GetOrAttachJNIEnvironment(JavaVM* jvm) {
363 JNIEnv* env = GetJNIEnvironment(jvm);
364 if (!env) {
365 int result = jvm->AttachCurrentThread(&env, nullptr);
366 CHECK_EQ(result, JNI_OK) << "thread attach failed";
367 struct VmDetacher {
368 VmDetacher(JavaVM* vm) : mVm(vm) {}
369 ~VmDetacher() { mVm->DetachCurrentThread(); }
370
371 private:
372 JavaVM* const mVm;
373 };
374 static thread_local VmDetacher detacher(jvm);
375 }
376 return env;
377}
378
379class PackageManagerShellCommandDataLoaderDataLoader : public android::dataloader::DataLoader {
380public:
381 PackageManagerShellCommandDataLoaderDataLoader(JavaVM* jvm) : mJvm(jvm) { CHECK(mJvm); }
382
383private:
384 // Lifecycle.
385 bool onCreate(const android::dataloader::DataLoaderParams& params,
386 android::dataloader::FilesystemConnectorPtr ifs,
387 android::dataloader::StatusListenerPtr statusListener,
388 android::dataloader::ServiceConnectorPtr,
389 android::dataloader::ServiceParamsPtr) final {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800390 CHECK(ifs) << "ifs can't be null";
391 CHECK(statusListener) << "statusListener can't be null";
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800392 mArgs = params.arguments();
393 mIfs = ifs;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800394 mStatusListener = statusListener;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800395 return true;
396 }
397 bool onStart() final { return true; }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800398 void onStop() final {
399 mStopReceiving = true;
400 eventfd_write(mEventFd, 1);
401 if (mReceiverThread.joinable()) {
402 mReceiverThread.join();
403 }
404 }
405 void onDestroy() final {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800406 // Make sure the receiver thread stopped.
407 CHECK(!mReceiverThread.joinable());
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800408 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800409
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800410 // Installation.
Songchun Fan9b753082020-02-26 13:08:06 -0800411 bool onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles) final {
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800412 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
413 const auto& jni = jniIds(env);
414
415 jobject shellCommand = env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
416 jni.pmscdLookupShellCommand,
417 env->NewStringUTF(mArgs.c_str()));
418 if (!shellCommand) {
419 ALOGE("Missing shell command.");
420 return false;
421 }
422
423 std::vector<char> buffer;
424 buffer.reserve(BUFFER_SIZE);
425
426 std::vector<IncFsDataBlock> blocks;
427 blocks.reserve(BLOCKS_COUNT);
428
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800429 unique_fd streamingFd;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700430 MetadataMode streamingMode;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800431 for (auto&& file : addedFiles) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800432 auto inputs = openInputs(env, jni, shellCommand, file.size, file.metadata);
433 if (inputs.empty()) {
434 ALOGE("Failed to open an input file for metadata: %.*s, final file name is: %s. "
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800435 "Error %d",
436 int(file.metadata.size), file.metadata.data, file.name, errno);
437 return false;
438 }
439
440 const auto fileId = IncFs_FileIdFromMetadata(file.metadata);
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800441 const auto incfsFd(mIfs->openWrite(fileId));
442 if (incfsFd < 0) {
443 ALOGE("Failed to open an IncFS file for metadata: %.*s, final file name is: %s. "
444 "Error %d",
445 int(file.metadata.size), file.metadata.data, file.name, errno);
446 return false;
447 }
448
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800449 for (auto&& input : inputs) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800450 if (input.streaming && !streamingFd.ok()) {
451 streamingFd.reset(dup(input.fd));
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700452 streamingMode = input.mode;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800453 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800454 if (!copyToIncFs(incfsFd, input.size, input.kind, input.fd, input.waitOnEof,
455 &buffer, &blocks)) {
456 ALOGE("Failed to copy data to IncFS file for metadata: %.*s, final file name "
457 "is: %s. "
458 "Error %d",
459 int(file.metadata.size), file.metadata.data, file.name, errno);
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800460 return false;
461 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800462 }
463 }
464
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800465 if (streamingFd.ok()) {
466 ALOGE("onPrepareImage: done, proceeding to streaming.");
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700467 return initStreaming(std::move(streamingFd), streamingMode);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800468 }
469
470 ALOGE("onPrepareImage: done.");
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800471 return true;
472 }
473
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800474 bool copyToIncFs(borrowed_fd incfsFd, IncFsSize size, IncFsBlockKind kind,
475 borrowed_fd incomingFd, bool waitOnEof, std::vector<char>* buffer,
476 std::vector<IncFsDataBlock>* blocks) {
477 IncFsSize remaining = size;
478 IncFsSize totalSize = 0;
479 IncFsBlockIndex blockIdx = 0;
480 while (remaining > 0) {
481 constexpr auto capacity = BUFFER_SIZE;
482 auto size = buffer->size();
483 if (capacity - size < INCFS_DATA_FILE_BLOCK_SIZE) {
484 if (!flashToIncFs(incfsFd, kind, false, &blockIdx, buffer, blocks)) {
485 return false;
486 }
487 continue;
488 }
489
490 auto toRead = std::min<IncFsSize>(remaining, capacity - size);
491 buffer->resize(size + toRead);
492 auto read = ::read(incomingFd.get(), buffer->data() + size, toRead);
493 if (read == 0) {
494 if (waitOnEof) {
495 // eof of stdin, waiting...
496 ALOGE("eof of stdin, waiting...: %d, remaining: %d, block: %d, read: %d",
497 int(totalSize), int(remaining), int(blockIdx), int(read));
498 using namespace std::chrono_literals;
499 std::this_thread::sleep_for(10ms);
500 continue;
501 }
502 break;
503 }
504 if (read < 0) {
505 return false;
506 }
507
508 buffer->resize(size + read);
509 remaining -= read;
510 totalSize += read;
511 }
512 if (!buffer->empty() && !flashToIncFs(incfsFd, kind, true, &blockIdx, buffer, blocks)) {
513 return false;
514 }
515 return true;
516 }
517
518 bool flashToIncFs(borrowed_fd incfsFd, IncFsBlockKind kind, bool eof, IncFsBlockIndex* blockIdx,
519 std::vector<char>* buffer, std::vector<IncFsDataBlock>* blocks) {
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800520 int consumed = 0;
521 const auto fullBlocks = buffer->size() / INCFS_DATA_FILE_BLOCK_SIZE;
522 for (int i = 0; i < fullBlocks; ++i) {
523 const auto inst = IncFsDataBlock{
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800524 .fileFd = incfsFd.get(),
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800525 .pageIndex = (*blockIdx)++,
526 .compression = INCFS_COMPRESSION_KIND_NONE,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800527 .kind = kind,
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800528 .dataSize = INCFS_DATA_FILE_BLOCK_SIZE,
529 .data = buffer->data() + consumed,
530 };
531 blocks->push_back(inst);
532 consumed += INCFS_DATA_FILE_BLOCK_SIZE;
533 }
534 const auto remain = buffer->size() - fullBlocks * INCFS_DATA_FILE_BLOCK_SIZE;
535 if (remain && eof) {
536 const auto inst = IncFsDataBlock{
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800537 .fileFd = incfsFd.get(),
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800538 .pageIndex = (*blockIdx)++,
539 .compression = INCFS_COMPRESSION_KIND_NONE,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800540 .kind = kind,
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800541 .dataSize = static_cast<uint16_t>(remain),
542 .data = buffer->data() + consumed,
543 };
544 blocks->push_back(inst);
545 consumed += remain;
546 }
547
Songchun Fan9b753082020-02-26 13:08:06 -0800548 auto res = mIfs->writeBlocks({blocks->data(), blocks->size()});
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800549
550 blocks->clear();
551 buffer->erase(buffer->begin(), buffer->begin() + consumed);
552
553 if (res < 0) {
554 ALOGE("Failed to write block to IncFS: %d", int(res));
555 return false;
556 }
557 return true;
558 }
559
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800560 // Read tracing.
561 struct TracedRead {
562 uint64_t timestampUs;
563 android::dataloader::FileId fileId;
564 uint32_t firstBlockIdx;
565 uint32_t count;
566 };
567
Songchun Fan9b753082020-02-26 13:08:06 -0800568 void onPageReads(android::dataloader::PageReads pageReads) final {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800569 auto trace = atrace_is_tag_enabled(ATRACE_TAG);
570 if (CC_LIKELY(!trace)) {
571 return;
572 }
573
574 TracedRead last = {};
575 for (auto&& read : pageReads) {
576 if (read.id != last.fileId || read.block != last.firstBlockIdx + last.count) {
577 traceRead(last);
578 last = TracedRead{
579 .timestampUs = read.bootClockTsUs,
580 .fileId = read.id,
581 .firstBlockIdx = (uint32_t)read.block,
582 .count = 1,
583 };
584 } else {
585 ++last.count;
586 }
587 }
588 traceRead(last);
589 }
590
591 void traceRead(const TracedRead& read) {
592 if (!read.count) {
593 return;
594 }
595
596 FileIdx fileIdx = convertFileIdToFileIndex(read.fileId);
597 auto str = android::base::StringPrintf("page_read: index=%lld count=%lld file=%d",
598 static_cast<long long>(read.firstBlockIdx),
599 static_cast<long long>(read.count),
600 static_cast<int>(fileIdx));
601 ATRACE_BEGIN(str.c_str());
602 ATRACE_END();
603 }
604
605 // Streaming.
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700606 bool initStreaming(unique_fd inout, MetadataMode mode) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800607 mEventFd.reset(eventfd(0, EFD_CLOEXEC));
608 if (mEventFd < 0) {
609 ALOGE("Failed to create eventfd.");
610 return false;
611 }
612
613 // Awaiting adb handshake.
614 char okay_buf[OKAY.size()];
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700615 if (!android::base::ReadFully(inout, okay_buf, OKAY.size())) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800616 ALOGE("Failed to receive OKAY. Abort.");
617 return false;
618 }
619 if (std::string_view(okay_buf, OKAY.size()) != OKAY) {
620 ALOGE("Received '%.*s', expecting '%.*s'", (int)OKAY.size(), okay_buf, (int)OKAY.size(),
621 OKAY.data());
622 return false;
623 }
624
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700625 {
626 std::lock_guard lock{mOutFdLock};
627 mOutFd.reset(::dup(inout));
628 if (mOutFd < 0) {
629 ALOGE("Failed to create streaming fd.");
630 }
631 }
632
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700633 mReceiverThread = std::thread(
634 [this, io = std::move(inout), mode]() mutable { receiver(std::move(io), mode); });
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800635 ALOGI("Started streaming...");
636 return true;
637 }
638
639 // IFS callbacks.
Songchun Fan9b753082020-02-26 13:08:06 -0800640 void onPendingReads(dataloader::PendingReads pendingReads) final {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700641 std::lock_guard lock{mOutFdLock};
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700642 if (mOutFd < 0) {
643 return;
644 }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800645 CHECK(mIfs);
646 for (auto&& pendingRead : pendingReads) {
647 const android::dataloader::FileId& fileId = pendingRead.id;
648 const auto blockIdx = static_cast<BlockIdx>(pendingRead.block);
649 /*
650 ALOGI("Missing: %d", (int) blockIdx);
651 */
652 FileIdx fileIdx = convertFileIdToFileIndex(fileId);
653 if (fileIdx < 0) {
654 ALOGE("Failed to handle event for fileid=%s. Ignore.",
655 android::incfs::toString(fileId).c_str());
656 continue;
657 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700658 if (mRequestedFiles.insert(fileIdx).second &&
659 !sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
660 mRequestedFiles.erase(fileIdx);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800661 }
662 sendRequest(mOutFd, BLOCK_MISSING, fileIdx, blockIdx);
663 }
664 }
665
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700666 void receiver(unique_fd inout, MetadataMode mode) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800667 std::vector<uint8_t> data;
668 std::vector<IncFsDataBlock> instructions;
669 std::unordered_map<FileIdx, unique_fd> writeFds;
670 while (!mStopReceiving) {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700671 const int res = waitForDataOrSignal(inout, mEventFd);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800672 if (res == 0) {
673 continue;
674 }
675 if (res < 0) {
676 ALOGE("Failed to poll. Abort.");
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700677 mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800678 break;
679 }
680 if (res == mEventFd) {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700681 ALOGE("Received stop signal. Sending EXIT to server.");
682 sendRequest(inout, EXIT);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800683 break;
684 }
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700685 if (!readChunk(inout, data)) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800686 ALOGE("Failed to read a message. Abort.");
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700687 mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800688 break;
689 }
690 auto remainingData = std::span(data);
691 while (!remainingData.empty()) {
692 auto header = readHeader(remainingData);
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700693 if (header.fileIdx == -1 && header.blockType == 0 && header.compressionType == 0 &&
694 header.blockIdx == 0 && header.blockSize == 0) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800695 ALOGI("Stop signal received. Sending exit command (remaining bytes: %d).",
696 int(remainingData.size()));
697
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700698 sendRequest(inout, EXIT);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800699 mStopReceiving = true;
700 break;
701 }
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700702 if (header.fileIdx < 0 || header.blockSize <= 0 || header.blockType < 0 ||
703 header.compressionType < 0 || header.blockIdx < 0) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800704 ALOGE("invalid header received. Abort.");
705 mStopReceiving = true;
706 break;
707 }
708 const FileIdx fileIdx = header.fileIdx;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700709 const android::dataloader::FileId fileId = convertFileIndexToFileId(mode, fileIdx);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800710 if (!android::incfs::isValidFileId(fileId)) {
711 ALOGE("Unknown data destination for file ID %d. "
712 "Ignore.",
713 header.fileIdx);
714 continue;
715 }
716
717 auto& writeFd = writeFds[fileIdx];
718 if (writeFd < 0) {
Songchun Fanb8ab0032020-02-26 11:02:37 -0800719 writeFd.reset(this->mIfs->openWrite(fileId));
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800720 if (writeFd < 0) {
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700721 ALOGE("Failed to open file %d for writing (%d). Aborting.", header.fileIdx,
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800722 -writeFd);
723 break;
724 }
725 }
726
727 const auto inst = IncFsDataBlock{
728 .fileFd = writeFd,
729 .pageIndex = static_cast<IncFsBlockIndex>(header.blockIdx),
730 .compression = static_cast<IncFsCompressionKind>(header.compressionType),
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700731 .kind = static_cast<IncFsBlockKind>(header.blockType),
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800732 .dataSize = static_cast<uint16_t>(header.blockSize),
733 .data = (const char*)remainingData.data(),
734 };
735 instructions.push_back(inst);
736 remainingData = remainingData.subspan(header.blockSize);
737 }
738 writeInstructions(instructions);
739 }
740 writeInstructions(instructions);
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700741
742 {
743 std::lock_guard lock{mOutFdLock};
744 mOutFd.reset();
745 }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800746 }
747
748 void writeInstructions(std::vector<IncFsDataBlock>& instructions) {
749 auto res = this->mIfs->writeBlocks(instructions);
750 if (res != instructions.size()) {
751 ALOGE("Dailed to write data to Incfs (res=%d when expecting %d)", res,
752 int(instructions.size()));
753 }
754 instructions.clear();
755 }
756
757 FileIdx convertFileIdToFileIndex(android::dataloader::FileId fileId) {
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700758 // FileId has format '\2FileIdx'.
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800759 const char* meta = (const char*)&fileId;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700760
761 int8_t mode = *meta;
762 if (mode != DATA_ONLY_STREAMING && mode != STREAMING) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800763 return -1;
764 }
765
766 int fileIdx;
767 auto res = std::from_chars(meta + 1, meta + sizeof(fileId), fileIdx);
768 if (res.ec != std::errc{} || fileIdx < std::numeric_limits<FileIdx>::min() ||
769 fileIdx > std::numeric_limits<FileIdx>::max()) {
770 return -1;
771 }
772
773 return FileIdx(fileIdx);
774 }
775
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700776 android::dataloader::FileId convertFileIndexToFileId(MetadataMode mode, FileIdx fileIdx) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800777 IncFsFileId fileId = {};
778 char* meta = (char*)&fileId;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700779 *meta = mode;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800780 if (auto [p, ec] = std::to_chars(meta + 1, meta + sizeof(fileId), fileIdx);
781 ec != std::errc()) {
782 return {};
783 }
784 return fileId;
785 }
786
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800787 JavaVM* const mJvm;
788 std::string mArgs;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800789 android::dataloader::FilesystemConnectorPtr mIfs = nullptr;
790 android::dataloader::StatusListenerPtr mStatusListener = nullptr;
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700791 std::mutex mOutFdLock;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800792 android::base::unique_fd mOutFd;
793 android::base::unique_fd mEventFd;
794 std::thread mReceiverThread;
795 std::atomic<bool> mStopReceiving = false;
796 /** Tracks which files have been requested */
797 std::unordered_set<FileIdx> mRequestedFiles;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800798};
799
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800800BlockHeader readHeader(std::span<uint8_t>& data) {
801 BlockHeader header;
802 if (data.size() < sizeof(header)) {
803 return header;
804 }
805
806 header.fileIdx = static_cast<FileIdx>(be16toh(*reinterpret_cast<const uint16_t*>(&data[0])));
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700807 header.blockType = static_cast<BlockType>(data[2]);
808 header.compressionType = static_cast<CompressionType>(data[3]);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800809 header.blockIdx = static_cast<BlockIdx>(be32toh(*reinterpret_cast<const uint32_t*>(&data[4])));
810 header.blockSize =
811 static_cast<BlockSize>(be16toh(*reinterpret_cast<const uint16_t*>(&data[8])));
812 data = data.subspan(sizeof(header));
813
814 return header;
815}
816
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800817static void nativeInitialize(JNIEnv* env, jclass klass) {
818 jniIds(env);
819}
820
821static const JNINativeMethod method_table[] = {
822 {"nativeInitialize", "()V", (void*)nativeInitialize},
823};
824
825} // namespace
826
827int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(
828 JNIEnv* env) {
829 android::dataloader::DataLoader::initialize(
830 [](auto jvm, const auto& params) -> android::dataloader::DataLoaderPtr {
831 if (params.type() == DATA_LOADER_TYPE_INCREMENTAL) {
832 // This DataLoader only supports incremental installations.
833 return std::make_unique<PackageManagerShellCommandDataLoaderDataLoader>(jvm);
834 }
835 return {};
836 });
837 return jniRegisterNativeMethods(env,
838 "com/android/server/pm/PackageManagerShellCommandDataLoader",
839 method_table, NELEM(method_table));
840}
841
842} // namespace android