blob: 6cf81335e52d974483017929539dcce577b7be26 [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;
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -070072 jmethodID pmscdGetStdIn;
Alex Buynytskyy04f73912020-02-10 08:34:18 -080073 jmethodID pmscdGetLocalFile;
74
Alex Buynytskyy04f73912020-02-10 08:34:18 -080075 JniIds(JNIEnv* env) {
76 packageManagerShellCommandDataLoader = (jclass)env->NewGlobalRef(
77 FindClassOrDie(env, "com/android/server/pm/PackageManagerShellCommandDataLoader"));
78 pmscdLookupShellCommand =
79 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader,
80 "lookupShellCommand",
81 "(Ljava/lang/String;)Landroid/os/ShellCommand;");
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -070082 pmscdGetStdIn = GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader,
83 "getStdIn", "(Landroid/os/ShellCommand;)I");
Alex Buynytskyy04f73912020-02-10 08:34:18 -080084 pmscdGetLocalFile =
85 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader, "getLocalFile",
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -070086 "(Landroid/os/ShellCommand;Ljava/lang/String;)I");
Alex Buynytskyy04f73912020-02-10 08:34:18 -080087 }
88};
89
90const JniIds& jniIds(JNIEnv* env) {
91 static const JniIds ids(env);
92 return ids;
93}
94
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080095struct BlockHeader {
96 FileIdx fileIdx = -1;
Alex Buynytskyye9d20f02020-03-20 10:45:51 -070097 BlockType blockType = -1;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080098 CompressionType compressionType = -1;
99 BlockIdx blockIdx = -1;
100 BlockSize blockSize = -1;
101} __attribute__((packed));
102
103static_assert(sizeof(BlockHeader) == HEADER_SIZE);
104
105static constexpr RequestType EXIT = 0;
106static constexpr RequestType BLOCK_MISSING = 1;
107static constexpr RequestType PREFETCH = 2;
108
109struct RequestCommand {
110 MagicType magic;
111 RequestType requestType;
112 FileIdx fileIdx;
113 BlockIdx blockIdx;
114} __attribute__((packed));
115
116static_assert(COMMAND_SIZE == sizeof(RequestCommand));
117
118static bool sendRequest(int fd, RequestType requestType, FileIdx fileIdx = -1,
119 BlockIdx blockIdx = -1) {
120 const RequestCommand command{.magic = INCR,
121 .requestType = static_cast<int16_t>(be16toh(requestType)),
122 .fileIdx = static_cast<int16_t>(be16toh(fileIdx)),
123 .blockIdx = static_cast<int32_t>(be32toh(blockIdx))};
124 return android::base::WriteFully(fd, &command, sizeof(command));
125}
126
127static int waitForDataOrSignal(int fd, int event_fd) {
128 struct pollfd pfds[2] = {{fd, POLLIN, 0}, {event_fd, POLLIN, 0}};
129 // Wait indefinitely until either data is ready or stop signal is received
130 int res = poll(pfds, 2, PollTimeoutMs);
131 if (res <= 0) {
132 return res;
133 }
134 // First check if there is a stop signal
135 if (pfds[1].revents == POLLIN) {
136 return event_fd;
137 }
138 // Otherwise check if incoming data is ready
139 if (pfds[0].revents == POLLIN) {
140 return fd;
141 }
142 return -1;
143}
144
145static bool readChunk(int fd, std::vector<uint8_t>& data) {
146 int32_t size;
147 if (!android::base::ReadFully(fd, &size, sizeof(size))) {
148 return false;
149 }
150 size = int32_t(be32toh(size));
151 if (size <= 0) {
152 return false;
153 }
154 data.resize(size);
155 return android::base::ReadFully(fd, data.data(), data.size());
156}
157
158BlockHeader readHeader(std::span<uint8_t>& data);
159
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700160static inline int32_t readLEInt32(borrowed_fd fd) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800161 int32_t result;
162 ReadFully(fd, &result, sizeof(result));
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700163 result = int32_t(le32toh(result));
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800164 return result;
165}
166
167static inline std::vector<char> readBytes(borrowed_fd fd) {
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700168 int32_t size = readLEInt32(fd);
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800169 std::vector<char> result(size);
170 ReadFully(fd, result.data(), size);
171 return result;
172}
173
174static inline int32_t skipIdSigHeaders(borrowed_fd fd) {
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700175 readLEInt32(fd); // version
176 readBytes(fd); // hashingInfo
177 readBytes(fd); // signingInfo
178 return readLEInt32(fd); // size of the verity tree
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800179}
180
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800181static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) {
182 constexpr int SHA256_DIGEST_SIZE = 32;
183 constexpr int digest_size = SHA256_DIGEST_SIZE;
184 constexpr int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
185
186 IncFsSize total_tree_block_count = 0;
187
188 auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
189 auto hash_block_count = block_count;
190 for (auto i = 0; hash_block_count > 1; i++) {
191 hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
192 total_tree_block_count += hash_block_count;
193 }
194 return total_tree_block_count * INCFS_DATA_FILE_BLOCK_SIZE;
195}
196
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700197enum MetadataMode : int8_t {
198 STDIN = 0,
199 LOCAL_FILE = 1,
200 DATA_ONLY_STREAMING = 2,
201 STREAMING = 3,
202};
203
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800204struct InputDesc {
205 unique_fd fd;
206 IncFsSize size;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800207 IncFsBlockKind kind = INCFS_BLOCK_KIND_DATA;
208 bool waitOnEof = false;
209 bool streaming = false;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700210 MetadataMode mode = STDIN;
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800211};
212using InputDescs = std::vector<InputDesc>;
213
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700214template <class T>
215std::optional<T> read(IncFsSpan& data) {
216 if (data.size < (int32_t)sizeof(T)) {
217 return {};
218 }
219 T res;
220 memcpy(&res, data.data, sizeof(res));
221 data.data += sizeof(res);
222 data.size -= sizeof(res);
223 return res;
224}
225
226static inline InputDescs openLocalFile(JNIEnv* env, const JniIds& jni, jobject shellCommand,
227 IncFsSize size, const std::string& filePath) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800228 InputDescs result;
229 result.reserve(2);
230
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800231 const std::string idsigPath = filePath + ".idsig";
232
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -0700233 unique_fd idsigFd{env->CallStaticIntMethod(jni.packageManagerShellCommandDataLoader,
234 jni.pmscdGetLocalFile, shellCommand,
235 env->NewStringUTF(idsigPath.c_str()))};
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800236 if (idsigFd.ok()) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800237 auto treeSize = verityTreeSizeForFile(size);
238 auto actualTreeSize = skipIdSigHeaders(idsigFd);
239 if (treeSize != actualTreeSize) {
240 ALOGE("Verity tree size mismatch: %d vs .idsig: %d.", int(treeSize),
241 int(actualTreeSize));
242 return {};
243 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800244 result.push_back(InputDesc{
245 .fd = std::move(idsigFd),
246 .size = treeSize,
247 .kind = INCFS_BLOCK_KIND_HASH,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800248 });
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800249 }
250
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -0700251 unique_fd fileFd{env->CallStaticIntMethod(jni.packageManagerShellCommandDataLoader,
252 jni.pmscdGetLocalFile, shellCommand,
253 env->NewStringUTF(filePath.c_str()))};
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800254 if (fileFd.ok()) {
255 result.push_back(InputDesc{
256 .fd = std::move(fileFd),
257 .size = size,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800258 });
259 }
260
261 return result;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800262}
263
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700264static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shellCommand,
265 IncFsSize size, IncFsSpan metadata) {
266 auto mode = read<int8_t>(metadata).value_or(STDIN);
267 if (mode == LOCAL_FILE) {
268 // local file and possibly signature
269 return openLocalFile(env, jni, shellCommand, size,
270 std::string(metadata.data, metadata.size));
271 }
272
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -0700273 unique_fd fd{env->CallStaticIntMethod(jni.packageManagerShellCommandDataLoader,
274 jni.pmscdGetStdIn, shellCommand)};
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700275 if (!fd.ok()) {
276 return {};
277 }
278
279 InputDescs result;
280 switch (mode) {
281 case STDIN: {
282 result.push_back(InputDesc{
283 .fd = std::move(fd),
284 .size = size,
285 .waitOnEof = true,
286 });
287 break;
288 }
289 case DATA_ONLY_STREAMING: {
290 // verity tree from stdin, rest is streaming
291 auto treeSize = verityTreeSizeForFile(size);
292 result.push_back(InputDesc{
293 .fd = std::move(fd),
294 .size = treeSize,
295 .kind = INCFS_BLOCK_KIND_HASH,
296 .waitOnEof = true,
297 .streaming = true,
298 .mode = DATA_ONLY_STREAMING,
299 });
300 break;
301 }
302 case STREAMING: {
303 result.push_back(InputDesc{
304 .fd = std::move(fd),
305 .size = 0,
306 .streaming = true,
307 .mode = STREAMING,
308 });
309 break;
310 }
311 }
312 return result;
313}
314
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800315static inline JNIEnv* GetJNIEnvironment(JavaVM* vm) {
316 JNIEnv* env;
317 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
318 return 0;
319 }
320 return env;
321}
322
323static inline JNIEnv* GetOrAttachJNIEnvironment(JavaVM* jvm) {
324 JNIEnv* env = GetJNIEnvironment(jvm);
325 if (!env) {
326 int result = jvm->AttachCurrentThread(&env, nullptr);
327 CHECK_EQ(result, JNI_OK) << "thread attach failed";
328 struct VmDetacher {
329 VmDetacher(JavaVM* vm) : mVm(vm) {}
330 ~VmDetacher() { mVm->DetachCurrentThread(); }
331
332 private:
333 JavaVM* const mVm;
334 };
335 static thread_local VmDetacher detacher(jvm);
336 }
337 return env;
338}
339
340class PackageManagerShellCommandDataLoaderDataLoader : public android::dataloader::DataLoader {
341public:
342 PackageManagerShellCommandDataLoaderDataLoader(JavaVM* jvm) : mJvm(jvm) { CHECK(mJvm); }
343
344private:
345 // Lifecycle.
346 bool onCreate(const android::dataloader::DataLoaderParams& params,
347 android::dataloader::FilesystemConnectorPtr ifs,
348 android::dataloader::StatusListenerPtr statusListener,
349 android::dataloader::ServiceConnectorPtr,
350 android::dataloader::ServiceParamsPtr) final {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800351 CHECK(ifs) << "ifs can't be null";
352 CHECK(statusListener) << "statusListener can't be null";
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800353 mArgs = params.arguments();
354 mIfs = ifs;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800355 mStatusListener = statusListener;
Alex Buynytskyy5e860ba2020-03-31 15:30:21 -0700356 mIfs->setParams({.readLogsEnabled = true});
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800357 return true;
358 }
359 bool onStart() final { return true; }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800360 void onStop() final {
361 mStopReceiving = true;
362 eventfd_write(mEventFd, 1);
363 if (mReceiverThread.joinable()) {
364 mReceiverThread.join();
365 }
366 }
367 void onDestroy() final {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800368 // Make sure the receiver thread stopped.
369 CHECK(!mReceiverThread.joinable());
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800370 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800371
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800372 // Installation.
Songchun Fan9b753082020-02-26 13:08:06 -0800373 bool onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles) final {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700374 ALOGE("onPrepareImage: start.");
375
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800376 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
377 const auto& jni = jniIds(env);
378
379 jobject shellCommand = env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
380 jni.pmscdLookupShellCommand,
381 env->NewStringUTF(mArgs.c_str()));
382 if (!shellCommand) {
383 ALOGE("Missing shell command.");
384 return false;
385 }
386
387 std::vector<char> buffer;
388 buffer.reserve(BUFFER_SIZE);
389
390 std::vector<IncFsDataBlock> blocks;
391 blocks.reserve(BLOCKS_COUNT);
392
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800393 unique_fd streamingFd;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700394 MetadataMode streamingMode;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800395 for (auto&& file : addedFiles) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800396 auto inputs = openInputs(env, jni, shellCommand, file.size, file.metadata);
397 if (inputs.empty()) {
398 ALOGE("Failed to open an input file for metadata: %.*s, final file name is: %s. "
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800399 "Error %d",
400 int(file.metadata.size), file.metadata.data, file.name, errno);
401 return false;
402 }
403
404 const auto fileId = IncFs_FileIdFromMetadata(file.metadata);
Yurii Zubrytskyie82cdd72020-04-01 12:19:26 -0700405 const base::unique_fd incfsFd(mIfs->openForSpecialOps(fileId).release());
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800406 if (incfsFd < 0) {
407 ALOGE("Failed to open an IncFS file for metadata: %.*s, final file name is: %s. "
408 "Error %d",
409 int(file.metadata.size), file.metadata.data, file.name, errno);
410 return false;
411 }
412
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800413 for (auto&& input : inputs) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800414 if (input.streaming && !streamingFd.ok()) {
415 streamingFd.reset(dup(input.fd));
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700416 streamingMode = input.mode;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800417 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800418 if (!copyToIncFs(incfsFd, input.size, input.kind, input.fd, input.waitOnEof,
419 &buffer, &blocks)) {
420 ALOGE("Failed to copy data to IncFS file for metadata: %.*s, final file name "
421 "is: %s. "
422 "Error %d",
423 int(file.metadata.size), file.metadata.data, file.name, errno);
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800424 return false;
425 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800426 }
427 }
428
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800429 if (streamingFd.ok()) {
430 ALOGE("onPrepareImage: done, proceeding to streaming.");
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700431 return initStreaming(std::move(streamingFd), streamingMode);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800432 }
433
434 ALOGE("onPrepareImage: done.");
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800435 return true;
436 }
437
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800438 bool copyToIncFs(borrowed_fd incfsFd, IncFsSize size, IncFsBlockKind kind,
439 borrowed_fd incomingFd, bool waitOnEof, std::vector<char>* buffer,
440 std::vector<IncFsDataBlock>* blocks) {
441 IncFsSize remaining = size;
442 IncFsSize totalSize = 0;
443 IncFsBlockIndex blockIdx = 0;
444 while (remaining > 0) {
445 constexpr auto capacity = BUFFER_SIZE;
446 auto size = buffer->size();
447 if (capacity - size < INCFS_DATA_FILE_BLOCK_SIZE) {
448 if (!flashToIncFs(incfsFd, kind, false, &blockIdx, buffer, blocks)) {
449 return false;
450 }
451 continue;
452 }
453
454 auto toRead = std::min<IncFsSize>(remaining, capacity - size);
455 buffer->resize(size + toRead);
456 auto read = ::read(incomingFd.get(), buffer->data() + size, toRead);
457 if (read == 0) {
458 if (waitOnEof) {
459 // eof of stdin, waiting...
460 ALOGE("eof of stdin, waiting...: %d, remaining: %d, block: %d, read: %d",
461 int(totalSize), int(remaining), int(blockIdx), int(read));
462 using namespace std::chrono_literals;
463 std::this_thread::sleep_for(10ms);
464 continue;
465 }
466 break;
467 }
468 if (read < 0) {
469 return false;
470 }
471
472 buffer->resize(size + read);
473 remaining -= read;
474 totalSize += read;
475 }
476 if (!buffer->empty() && !flashToIncFs(incfsFd, kind, true, &blockIdx, buffer, blocks)) {
477 return false;
478 }
479 return true;
480 }
481
482 bool flashToIncFs(borrowed_fd incfsFd, IncFsBlockKind kind, bool eof, IncFsBlockIndex* blockIdx,
483 std::vector<char>* buffer, std::vector<IncFsDataBlock>* blocks) {
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800484 int consumed = 0;
485 const auto fullBlocks = buffer->size() / INCFS_DATA_FILE_BLOCK_SIZE;
486 for (int i = 0; i < fullBlocks; ++i) {
487 const auto inst = IncFsDataBlock{
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800488 .fileFd = incfsFd.get(),
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800489 .pageIndex = (*blockIdx)++,
490 .compression = INCFS_COMPRESSION_KIND_NONE,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800491 .kind = kind,
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800492 .dataSize = INCFS_DATA_FILE_BLOCK_SIZE,
493 .data = buffer->data() + consumed,
494 };
495 blocks->push_back(inst);
496 consumed += INCFS_DATA_FILE_BLOCK_SIZE;
497 }
498 const auto remain = buffer->size() - fullBlocks * INCFS_DATA_FILE_BLOCK_SIZE;
499 if (remain && eof) {
500 const auto inst = IncFsDataBlock{
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800501 .fileFd = incfsFd.get(),
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800502 .pageIndex = (*blockIdx)++,
503 .compression = INCFS_COMPRESSION_KIND_NONE,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800504 .kind = kind,
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800505 .dataSize = static_cast<uint16_t>(remain),
506 .data = buffer->data() + consumed,
507 };
508 blocks->push_back(inst);
509 consumed += remain;
510 }
511
Songchun Fan9b753082020-02-26 13:08:06 -0800512 auto res = mIfs->writeBlocks({blocks->data(), blocks->size()});
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800513
514 blocks->clear();
515 buffer->erase(buffer->begin(), buffer->begin() + consumed);
516
517 if (res < 0) {
518 ALOGE("Failed to write block to IncFS: %d", int(res));
519 return false;
520 }
521 return true;
522 }
523
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800524 // Read tracing.
525 struct TracedRead {
526 uint64_t timestampUs;
527 android::dataloader::FileId fileId;
528 uint32_t firstBlockIdx;
529 uint32_t count;
530 };
531
Songchun Fan9b753082020-02-26 13:08:06 -0800532 void onPageReads(android::dataloader::PageReads pageReads) final {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800533 auto trace = atrace_is_tag_enabled(ATRACE_TAG);
534 if (CC_LIKELY(!trace)) {
535 return;
536 }
537
538 TracedRead last = {};
539 for (auto&& read : pageReads) {
540 if (read.id != last.fileId || read.block != last.firstBlockIdx + last.count) {
541 traceRead(last);
542 last = TracedRead{
543 .timestampUs = read.bootClockTsUs,
544 .fileId = read.id,
545 .firstBlockIdx = (uint32_t)read.block,
546 .count = 1,
547 };
548 } else {
549 ++last.count;
550 }
551 }
552 traceRead(last);
553 }
554
555 void traceRead(const TracedRead& read) {
556 if (!read.count) {
557 return;
558 }
559
560 FileIdx fileIdx = convertFileIdToFileIndex(read.fileId);
561 auto str = android::base::StringPrintf("page_read: index=%lld count=%lld file=%d",
562 static_cast<long long>(read.firstBlockIdx),
563 static_cast<long long>(read.count),
564 static_cast<int>(fileIdx));
565 ATRACE_BEGIN(str.c_str());
566 ATRACE_END();
567 }
568
569 // Streaming.
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700570 bool initStreaming(unique_fd inout, MetadataMode mode) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800571 mEventFd.reset(eventfd(0, EFD_CLOEXEC));
572 if (mEventFd < 0) {
573 ALOGE("Failed to create eventfd.");
574 return false;
575 }
576
577 // Awaiting adb handshake.
578 char okay_buf[OKAY.size()];
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700579 if (!android::base::ReadFully(inout, okay_buf, OKAY.size())) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800580 ALOGE("Failed to receive OKAY. Abort.");
581 return false;
582 }
583 if (std::string_view(okay_buf, OKAY.size()) != OKAY) {
584 ALOGE("Received '%.*s', expecting '%.*s'", (int)OKAY.size(), okay_buf, (int)OKAY.size(),
585 OKAY.data());
586 return false;
587 }
588
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700589 {
590 std::lock_guard lock{mOutFdLock};
591 mOutFd.reset(::dup(inout));
592 if (mOutFd < 0) {
593 ALOGE("Failed to create streaming fd.");
594 }
595 }
596
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700597 mReceiverThread = std::thread(
598 [this, io = std::move(inout), mode]() mutable { receiver(std::move(io), mode); });
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800599 ALOGI("Started streaming...");
600 return true;
601 }
602
603 // IFS callbacks.
Songchun Fan9b753082020-02-26 13:08:06 -0800604 void onPendingReads(dataloader::PendingReads pendingReads) final {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700605 std::lock_guard lock{mOutFdLock};
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700606 if (mOutFd < 0) {
607 return;
608 }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800609 CHECK(mIfs);
610 for (auto&& pendingRead : pendingReads) {
611 const android::dataloader::FileId& fileId = pendingRead.id;
612 const auto blockIdx = static_cast<BlockIdx>(pendingRead.block);
613 /*
614 ALOGI("Missing: %d", (int) blockIdx);
615 */
616 FileIdx fileIdx = convertFileIdToFileIndex(fileId);
617 if (fileIdx < 0) {
618 ALOGE("Failed to handle event for fileid=%s. Ignore.",
619 android::incfs::toString(fileId).c_str());
620 continue;
621 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700622 if (mRequestedFiles.insert(fileIdx).second &&
623 !sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
624 mRequestedFiles.erase(fileIdx);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800625 }
626 sendRequest(mOutFd, BLOCK_MISSING, fileIdx, blockIdx);
627 }
628 }
629
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700630 void receiver(unique_fd inout, MetadataMode mode) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800631 std::vector<uint8_t> data;
632 std::vector<IncFsDataBlock> instructions;
633 std::unordered_map<FileIdx, unique_fd> writeFds;
634 while (!mStopReceiving) {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700635 const int res = waitForDataOrSignal(inout, mEventFd);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800636 if (res == 0) {
637 continue;
638 }
639 if (res < 0) {
640 ALOGE("Failed to poll. Abort.");
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700641 mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800642 break;
643 }
644 if (res == mEventFd) {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700645 ALOGE("Received stop signal. Sending EXIT to server.");
646 sendRequest(inout, EXIT);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800647 break;
648 }
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700649 if (!readChunk(inout, data)) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800650 ALOGE("Failed to read a message. Abort.");
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700651 mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800652 break;
653 }
654 auto remainingData = std::span(data);
655 while (!remainingData.empty()) {
656 auto header = readHeader(remainingData);
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700657 if (header.fileIdx == -1 && header.blockType == 0 && header.compressionType == 0 &&
658 header.blockIdx == 0 && header.blockSize == 0) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800659 ALOGI("Stop signal received. Sending exit command (remaining bytes: %d).",
660 int(remainingData.size()));
661
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700662 sendRequest(inout, EXIT);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800663 mStopReceiving = true;
664 break;
665 }
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700666 if (header.fileIdx < 0 || header.blockSize <= 0 || header.blockType < 0 ||
667 header.compressionType < 0 || header.blockIdx < 0) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800668 ALOGE("invalid header received. Abort.");
669 mStopReceiving = true;
670 break;
671 }
672 const FileIdx fileIdx = header.fileIdx;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700673 const android::dataloader::FileId fileId = convertFileIndexToFileId(mode, fileIdx);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800674 if (!android::incfs::isValidFileId(fileId)) {
675 ALOGE("Unknown data destination for file ID %d. "
676 "Ignore.",
677 header.fileIdx);
678 continue;
679 }
680
681 auto& writeFd = writeFds[fileIdx];
682 if (writeFd < 0) {
Yurii Zubrytskyie82cdd72020-04-01 12:19:26 -0700683 writeFd.reset(this->mIfs->openForSpecialOps(fileId).release());
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800684 if (writeFd < 0) {
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700685 ALOGE("Failed to open file %d for writing (%d). Aborting.", header.fileIdx,
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800686 -writeFd);
687 break;
688 }
689 }
690
691 const auto inst = IncFsDataBlock{
692 .fileFd = writeFd,
693 .pageIndex = static_cast<IncFsBlockIndex>(header.blockIdx),
694 .compression = static_cast<IncFsCompressionKind>(header.compressionType),
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700695 .kind = static_cast<IncFsBlockKind>(header.blockType),
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800696 .dataSize = static_cast<uint16_t>(header.blockSize),
697 .data = (const char*)remainingData.data(),
698 };
699 instructions.push_back(inst);
700 remainingData = remainingData.subspan(header.blockSize);
701 }
702 writeInstructions(instructions);
703 }
704 writeInstructions(instructions);
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700705
706 {
707 std::lock_guard lock{mOutFdLock};
708 mOutFd.reset();
709 }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800710 }
711
712 void writeInstructions(std::vector<IncFsDataBlock>& instructions) {
713 auto res = this->mIfs->writeBlocks(instructions);
714 if (res != instructions.size()) {
715 ALOGE("Dailed to write data to Incfs (res=%d when expecting %d)", res,
716 int(instructions.size()));
717 }
718 instructions.clear();
719 }
720
721 FileIdx convertFileIdToFileIndex(android::dataloader::FileId fileId) {
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700722 // FileId has format '\2FileIdx'.
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800723 const char* meta = (const char*)&fileId;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700724
725 int8_t mode = *meta;
726 if (mode != DATA_ONLY_STREAMING && mode != STREAMING) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800727 return -1;
728 }
729
730 int fileIdx;
731 auto res = std::from_chars(meta + 1, meta + sizeof(fileId), fileIdx);
732 if (res.ec != std::errc{} || fileIdx < std::numeric_limits<FileIdx>::min() ||
733 fileIdx > std::numeric_limits<FileIdx>::max()) {
734 return -1;
735 }
736
737 return FileIdx(fileIdx);
738 }
739
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700740 android::dataloader::FileId convertFileIndexToFileId(MetadataMode mode, FileIdx fileIdx) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800741 IncFsFileId fileId = {};
742 char* meta = (char*)&fileId;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700743 *meta = mode;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800744 if (auto [p, ec] = std::to_chars(meta + 1, meta + sizeof(fileId), fileIdx);
745 ec != std::errc()) {
746 return {};
747 }
748 return fileId;
749 }
750
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800751 JavaVM* const mJvm;
752 std::string mArgs;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800753 android::dataloader::FilesystemConnectorPtr mIfs = nullptr;
754 android::dataloader::StatusListenerPtr mStatusListener = nullptr;
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700755 std::mutex mOutFdLock;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800756 android::base::unique_fd mOutFd;
757 android::base::unique_fd mEventFd;
758 std::thread mReceiverThread;
759 std::atomic<bool> mStopReceiving = false;
760 /** Tracks which files have been requested */
761 std::unordered_set<FileIdx> mRequestedFiles;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800762};
763
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800764BlockHeader readHeader(std::span<uint8_t>& data) {
765 BlockHeader header;
766 if (data.size() < sizeof(header)) {
767 return header;
768 }
769
770 header.fileIdx = static_cast<FileIdx>(be16toh(*reinterpret_cast<const uint16_t*>(&data[0])));
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700771 header.blockType = static_cast<BlockType>(data[2]);
772 header.compressionType = static_cast<CompressionType>(data[3]);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800773 header.blockIdx = static_cast<BlockIdx>(be32toh(*reinterpret_cast<const uint32_t*>(&data[4])));
774 header.blockSize =
775 static_cast<BlockSize>(be16toh(*reinterpret_cast<const uint16_t*>(&data[8])));
776 data = data.subspan(sizeof(header));
777
778 return header;
779}
780
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800781static void nativeInitialize(JNIEnv* env, jclass klass) {
782 jniIds(env);
783}
784
785static const JNINativeMethod method_table[] = {
786 {"nativeInitialize", "()V", (void*)nativeInitialize},
787};
788
789} // namespace
790
791int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(
792 JNIEnv* env) {
793 android::dataloader::DataLoader::initialize(
794 [](auto jvm, const auto& params) -> android::dataloader::DataLoaderPtr {
795 if (params.type() == DATA_LOADER_TYPE_INCREMENTAL) {
796 // This DataLoader only supports incremental installations.
797 return std::make_unique<PackageManagerShellCommandDataLoaderDataLoader>(jvm);
798 }
799 return {};
800 });
801 return jniRegisterNativeMethods(env,
802 "com/android/server/pm/PackageManagerShellCommandDataLoader",
803 method_table, NELEM(method_table));
804}
805
806} // namespace android