blob: e904645bda8f8ed6bbef4da3dae08ab64692f69a [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 Buynytskyy74247b92020-05-12 17:14:09 -070021#include <android-base/no_destructor.h>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080022#include <android-base/stringprintf.h>
Alex Buynytskyy04f73912020-02-10 08:34:18 -080023#include <android-base/unique_fd.h>
Songchun Fanb8ab0032020-02-26 11:02:37 -080024#include <core_jni_helpers.h>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080025#include <cutils/trace.h>
Songchun Fanb8ab0032020-02-26 11:02:37 -080026#include <endian.h>
27#include <nativehelper/JNIHelp.h>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080028#include <sys/eventfd.h>
29#include <sys/poll.h>
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -080030
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080031#include <charconv>
Alex Buynytskyy04f73912020-02-10 08:34:18 -080032#include <chrono>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080033#include <span>
34#include <string>
Alex Buynytskyy04f73912020-02-10 08:34:18 -080035#include <thread>
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080036#include <unordered_map>
37#include <unordered_set>
Alex Buynytskyy04f73912020-02-10 08:34:18 -080038
Songchun Fanb8ab0032020-02-26 11:02:37 -080039#include "dataloader.h"
40
Alex Buynytskyy04f73912020-02-10 08:34:18 -080041namespace android {
42
43namespace {
44
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -080045using android::base::borrowed_fd;
46using android::base::ReadFully;
Alex Buynytskyy04f73912020-02-10 08:34:18 -080047using android::base::unique_fd;
48
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080049using namespace std::literals;
50
51using BlockSize = int16_t;
52using FileIdx = int16_t;
53using BlockIdx = int32_t;
54using NumBlocks = int32_t;
Alex Buynytskyye9d20f02020-03-20 10:45:51 -070055using BlockType = int8_t;
56using CompressionType = int8_t;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080057using RequestType = int16_t;
58using MagicType = uint32_t;
59
Alex Buynytskyy04f73912020-02-10 08:34:18 -080060static constexpr int BUFFER_SIZE = 256 * 1024;
61static constexpr int BLOCKS_COUNT = BUFFER_SIZE / INCFS_DATA_FILE_BLOCK_SIZE;
62
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080063static constexpr int COMMAND_SIZE = 4 + 2 + 2 + 4; // bytes
Alex Buynytskyye9d20f02020-03-20 10:45:51 -070064static constexpr int HEADER_SIZE = 2 + 1 + 1 + 4 + 2; // bytes
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080065static constexpr std::string_view OKAY = "OKAY"sv;
66static constexpr MagicType INCR = 0x52434e49; // BE INCR
67
68static constexpr auto PollTimeoutMs = 5000;
Alex Buynytskyy74247b92020-05-12 17:14:09 -070069static constexpr auto TraceTagCheckInterval = 1s;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080070
Alex Buynytskyy04f73912020-02-10 08:34:18 -080071struct JniIds {
72 jclass packageManagerShellCommandDataLoader;
73 jmethodID pmscdLookupShellCommand;
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -070074 jmethodID pmscdGetStdIn;
Alex Buynytskyy04f73912020-02-10 08:34:18 -080075 jmethodID pmscdGetLocalFile;
76
Alex Buynytskyy04f73912020-02-10 08:34:18 -080077 JniIds(JNIEnv* env) {
78 packageManagerShellCommandDataLoader = (jclass)env->NewGlobalRef(
79 FindClassOrDie(env, "com/android/server/pm/PackageManagerShellCommandDataLoader"));
80 pmscdLookupShellCommand =
81 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader,
82 "lookupShellCommand",
83 "(Ljava/lang/String;)Landroid/os/ShellCommand;");
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -070084 pmscdGetStdIn = GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader,
85 "getStdIn", "(Landroid/os/ShellCommand;)I");
Alex Buynytskyy04f73912020-02-10 08:34:18 -080086 pmscdGetLocalFile =
87 GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader, "getLocalFile",
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -070088 "(Landroid/os/ShellCommand;Ljava/lang/String;)I");
Alex Buynytskyy04f73912020-02-10 08:34:18 -080089 }
90};
91
92const JniIds& jniIds(JNIEnv* env) {
93 static const JniIds ids(env);
94 return ids;
95}
96
Alex Buynytskyy17d9da02020-02-12 16:03:30 -080097struct BlockHeader {
98 FileIdx fileIdx = -1;
Alex Buynytskyye9d20f02020-03-20 10:45:51 -070099 BlockType blockType = -1;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800100 CompressionType compressionType = -1;
101 BlockIdx blockIdx = -1;
102 BlockSize blockSize = -1;
103} __attribute__((packed));
104
105static_assert(sizeof(BlockHeader) == HEADER_SIZE);
106
107static constexpr RequestType EXIT = 0;
108static constexpr RequestType BLOCK_MISSING = 1;
109static constexpr RequestType PREFETCH = 2;
110
111struct RequestCommand {
112 MagicType magic;
113 RequestType requestType;
114 FileIdx fileIdx;
115 BlockIdx blockIdx;
116} __attribute__((packed));
117
118static_assert(COMMAND_SIZE == sizeof(RequestCommand));
119
120static bool sendRequest(int fd, RequestType requestType, FileIdx fileIdx = -1,
121 BlockIdx blockIdx = -1) {
122 const RequestCommand command{.magic = INCR,
123 .requestType = static_cast<int16_t>(be16toh(requestType)),
124 .fileIdx = static_cast<int16_t>(be16toh(fileIdx)),
125 .blockIdx = static_cast<int32_t>(be32toh(blockIdx))};
126 return android::base::WriteFully(fd, &command, sizeof(command));
127}
128
129static int waitForDataOrSignal(int fd, int event_fd) {
130 struct pollfd pfds[2] = {{fd, POLLIN, 0}, {event_fd, POLLIN, 0}};
131 // Wait indefinitely until either data is ready or stop signal is received
132 int res = poll(pfds, 2, PollTimeoutMs);
133 if (res <= 0) {
134 return res;
135 }
136 // First check if there is a stop signal
137 if (pfds[1].revents == POLLIN) {
138 return event_fd;
139 }
140 // Otherwise check if incoming data is ready
141 if (pfds[0].revents == POLLIN) {
142 return fd;
143 }
144 return -1;
145}
146
147static bool readChunk(int fd, std::vector<uint8_t>& data) {
148 int32_t size;
149 if (!android::base::ReadFully(fd, &size, sizeof(size))) {
150 return false;
151 }
152 size = int32_t(be32toh(size));
153 if (size <= 0) {
154 return false;
155 }
156 data.resize(size);
157 return android::base::ReadFully(fd, data.data(), data.size());
158}
159
160BlockHeader readHeader(std::span<uint8_t>& data);
161
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700162static inline int32_t readLEInt32(borrowed_fd fd) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800163 int32_t result;
164 ReadFully(fd, &result, sizeof(result));
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700165 result = int32_t(le32toh(result));
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800166 return result;
167}
168
169static inline std::vector<char> readBytes(borrowed_fd fd) {
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700170 int32_t size = readLEInt32(fd);
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800171 std::vector<char> result(size);
172 ReadFully(fd, result.data(), size);
173 return result;
174}
175
176static inline int32_t skipIdSigHeaders(borrowed_fd fd) {
Alex Buynytskyyf5e605a2020-03-13 13:31:12 -0700177 readLEInt32(fd); // version
178 readBytes(fd); // hashingInfo
179 readBytes(fd); // signingInfo
180 return readLEInt32(fd); // size of the verity tree
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800181}
182
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800183static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) {
184 constexpr int SHA256_DIGEST_SIZE = 32;
185 constexpr int digest_size = SHA256_DIGEST_SIZE;
186 constexpr int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
187
188 IncFsSize total_tree_block_count = 0;
189
190 auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
191 auto hash_block_count = block_count;
192 for (auto i = 0; hash_block_count > 1; i++) {
193 hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
194 total_tree_block_count += hash_block_count;
195 }
196 return total_tree_block_count * INCFS_DATA_FILE_BLOCK_SIZE;
197}
198
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700199enum MetadataMode : int8_t {
200 STDIN = 0,
201 LOCAL_FILE = 1,
202 DATA_ONLY_STREAMING = 2,
203 STREAMING = 3,
204};
205
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800206struct InputDesc {
207 unique_fd fd;
208 IncFsSize size;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800209 IncFsBlockKind kind = INCFS_BLOCK_KIND_DATA;
210 bool waitOnEof = false;
211 bool streaming = false;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700212 MetadataMode mode = STDIN;
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800213};
214using InputDescs = std::vector<InputDesc>;
215
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700216template <class T>
217std::optional<T> read(IncFsSpan& data) {
218 if (data.size < (int32_t)sizeof(T)) {
219 return {};
220 }
221 T res;
222 memcpy(&res, data.data, sizeof(res));
223 data.data += sizeof(res);
224 data.size -= sizeof(res);
225 return res;
226}
227
228static inline InputDescs openLocalFile(JNIEnv* env, const JniIds& jni, jobject shellCommand,
229 IncFsSize size, const std::string& filePath) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800230 InputDescs result;
231 result.reserve(2);
232
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800233 const std::string idsigPath = filePath + ".idsig";
234
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -0700235 unique_fd idsigFd{env->CallStaticIntMethod(jni.packageManagerShellCommandDataLoader,
236 jni.pmscdGetLocalFile, shellCommand,
237 env->NewStringUTF(idsigPath.c_str()))};
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800238 if (idsigFd.ok()) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800239 auto treeSize = verityTreeSizeForFile(size);
240 auto actualTreeSize = skipIdSigHeaders(idsigFd);
241 if (treeSize != actualTreeSize) {
242 ALOGE("Verity tree size mismatch: %d vs .idsig: %d.", int(treeSize),
243 int(actualTreeSize));
244 return {};
245 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800246 result.push_back(InputDesc{
247 .fd = std::move(idsigFd),
248 .size = treeSize,
249 .kind = INCFS_BLOCK_KIND_HASH,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800250 });
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800251 }
252
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -0700253 unique_fd fileFd{env->CallStaticIntMethod(jni.packageManagerShellCommandDataLoader,
254 jni.pmscdGetLocalFile, shellCommand,
255 env->NewStringUTF(filePath.c_str()))};
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800256 if (fileFd.ok()) {
257 result.push_back(InputDesc{
258 .fd = std::move(fileFd),
259 .size = size,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800260 });
261 }
262
263 return result;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800264}
265
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700266static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shellCommand,
267 IncFsSize size, IncFsSpan metadata) {
268 auto mode = read<int8_t>(metadata).value_or(STDIN);
269 if (mode == LOCAL_FILE) {
270 // local file and possibly signature
271 return openLocalFile(env, jni, shellCommand, size,
272 std::string(metadata.data, metadata.size));
273 }
274
Alex Buynytskyyb3e7e292020-04-23 12:42:46 -0700275 unique_fd fd{env->CallStaticIntMethod(jni.packageManagerShellCommandDataLoader,
276 jni.pmscdGetStdIn, shellCommand)};
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700277 if (!fd.ok()) {
278 return {};
279 }
280
281 InputDescs result;
282 switch (mode) {
283 case STDIN: {
284 result.push_back(InputDesc{
285 .fd = std::move(fd),
286 .size = size,
287 .waitOnEof = true,
288 });
289 break;
290 }
291 case DATA_ONLY_STREAMING: {
292 // verity tree from stdin, rest is streaming
293 auto treeSize = verityTreeSizeForFile(size);
294 result.push_back(InputDesc{
295 .fd = std::move(fd),
296 .size = treeSize,
297 .kind = INCFS_BLOCK_KIND_HASH,
298 .waitOnEof = true,
299 .streaming = true,
300 .mode = DATA_ONLY_STREAMING,
301 });
302 break;
303 }
304 case STREAMING: {
305 result.push_back(InputDesc{
306 .fd = std::move(fd),
307 .size = 0,
308 .streaming = true,
309 .mode = STREAMING,
310 });
311 break;
312 }
313 }
314 return result;
315}
316
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800317static inline JNIEnv* GetJNIEnvironment(JavaVM* vm) {
318 JNIEnv* env;
319 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
320 return 0;
321 }
322 return env;
323}
324
325static inline JNIEnv* GetOrAttachJNIEnvironment(JavaVM* jvm) {
326 JNIEnv* env = GetJNIEnvironment(jvm);
327 if (!env) {
328 int result = jvm->AttachCurrentThread(&env, nullptr);
329 CHECK_EQ(result, JNI_OK) << "thread attach failed";
330 struct VmDetacher {
331 VmDetacher(JavaVM* vm) : mVm(vm) {}
332 ~VmDetacher() { mVm->DetachCurrentThread(); }
333
334 private:
335 JavaVM* const mVm;
336 };
337 static thread_local VmDetacher detacher(jvm);
338 }
339 return env;
340}
341
Alex Buynytskyy74247b92020-05-12 17:14:09 -0700342class PMSCDataLoader;
343
344struct OnTraceChanged {
345 OnTraceChanged();
346 ~OnTraceChanged() {
347 mRunning = false;
348 mChecker.join();
349 }
350
351 void registerCallback(PMSCDataLoader* callback) {
352 std::unique_lock lock(mMutex);
353 mCallbacks.insert(callback);
354 }
355
356 void unregisterCallback(PMSCDataLoader* callback) {
357 std::unique_lock lock(mMutex);
358 mCallbacks.erase(callback);
359 }
360
361private:
362 std::mutex mMutex;
363 std::unordered_set<PMSCDataLoader*> mCallbacks;
364 std::atomic<bool> mRunning{true};
365 std::thread mChecker;
366};
367
368static OnTraceChanged& onTraceChanged() {
369 static android::base::NoDestructor<OnTraceChanged> instance;
370 return *instance;
371}
372
373class PMSCDataLoader : public android::dataloader::DataLoader {
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800374public:
Alex Buynytskyy74247b92020-05-12 17:14:09 -0700375 PMSCDataLoader(JavaVM* jvm) : mJvm(jvm) { CHECK(mJvm); }
376 ~PMSCDataLoader() { onTraceChanged().unregisterCallback(this); }
377
378 void updateReadLogsState(const bool enabled) {
379 if (enabled != mReadLogsEnabled.exchange(enabled)) {
380 mIfs->setParams({.readLogsEnabled = enabled});
381 }
382 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800383
384private:
385 // Lifecycle.
386 bool onCreate(const android::dataloader::DataLoaderParams& params,
387 android::dataloader::FilesystemConnectorPtr ifs,
388 android::dataloader::StatusListenerPtr statusListener,
389 android::dataloader::ServiceConnectorPtr,
390 android::dataloader::ServiceParamsPtr) final {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800391 CHECK(ifs) << "ifs can't be null";
392 CHECK(statusListener) << "statusListener can't be null";
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800393 mArgs = params.arguments();
394 mIfs = ifs;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800395 mStatusListener = statusListener;
Alex Buynytskyy74247b92020-05-12 17:14:09 -0700396 updateReadLogsState(atrace_is_tag_enabled(ATRACE_TAG));
397 onTraceChanged().registerCallback(this);
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800398 return true;
399 }
400 bool onStart() final { return true; }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800401 void onStop() final {
402 mStopReceiving = true;
403 eventfd_write(mEventFd, 1);
404 if (mReceiverThread.joinable()) {
405 mReceiverThread.join();
406 }
407 }
408 void onDestroy() final {
Alex Buynytskyy74247b92020-05-12 17:14:09 -0700409 onTraceChanged().unregisterCallback(this);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800410 // Make sure the receiver thread stopped.
411 CHECK(!mReceiverThread.joinable());
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800412 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800413
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800414 // Installation.
Songchun Fan9b753082020-02-26 13:08:06 -0800415 bool onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles) final {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700416 ALOGE("onPrepareImage: start.");
417
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800418 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
419 const auto& jni = jniIds(env);
420
421 jobject shellCommand = env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
422 jni.pmscdLookupShellCommand,
423 env->NewStringUTF(mArgs.c_str()));
424 if (!shellCommand) {
425 ALOGE("Missing shell command.");
426 return false;
427 }
428
429 std::vector<char> buffer;
430 buffer.reserve(BUFFER_SIZE);
431
432 std::vector<IncFsDataBlock> blocks;
433 blocks.reserve(BLOCKS_COUNT);
434
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800435 unique_fd streamingFd;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700436 MetadataMode streamingMode;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800437 for (auto&& file : addedFiles) {
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800438 auto inputs = openInputs(env, jni, shellCommand, file.size, file.metadata);
439 if (inputs.empty()) {
440 ALOGE("Failed to open an input file for metadata: %.*s, final file name is: %s. "
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800441 "Error %d",
442 int(file.metadata.size), file.metadata.data, file.name, errno);
443 return false;
444 }
445
446 const auto fileId = IncFs_FileIdFromMetadata(file.metadata);
Yurii Zubrytskyie82cdd72020-04-01 12:19:26 -0700447 const base::unique_fd incfsFd(mIfs->openForSpecialOps(fileId).release());
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800448 if (incfsFd < 0) {
449 ALOGE("Failed to open an IncFS file for metadata: %.*s, final file name is: %s. "
450 "Error %d",
451 int(file.metadata.size), file.metadata.data, file.name, errno);
452 return false;
453 }
454
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800455 for (auto&& input : inputs) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800456 if (input.streaming && !streamingFd.ok()) {
457 streamingFd.reset(dup(input.fd));
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700458 streamingMode = input.mode;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800459 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800460 if (!copyToIncFs(incfsFd, input.size, input.kind, input.fd, input.waitOnEof,
461 &buffer, &blocks)) {
462 ALOGE("Failed to copy data to IncFS file for metadata: %.*s, final file name "
463 "is: %s. "
464 "Error %d",
465 int(file.metadata.size), file.metadata.data, file.name, errno);
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800466 return false;
467 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800468 }
469 }
470
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800471 if (streamingFd.ok()) {
472 ALOGE("onPrepareImage: done, proceeding to streaming.");
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700473 return initStreaming(std::move(streamingFd), streamingMode);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800474 }
475
476 ALOGE("onPrepareImage: done.");
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800477 return true;
478 }
479
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800480 bool copyToIncFs(borrowed_fd incfsFd, IncFsSize size, IncFsBlockKind kind,
481 borrowed_fd incomingFd, bool waitOnEof, std::vector<char>* buffer,
482 std::vector<IncFsDataBlock>* blocks) {
483 IncFsSize remaining = size;
484 IncFsSize totalSize = 0;
485 IncFsBlockIndex blockIdx = 0;
486 while (remaining > 0) {
487 constexpr auto capacity = BUFFER_SIZE;
488 auto size = buffer->size();
489 if (capacity - size < INCFS_DATA_FILE_BLOCK_SIZE) {
490 if (!flashToIncFs(incfsFd, kind, false, &blockIdx, buffer, blocks)) {
491 return false;
492 }
493 continue;
494 }
495
496 auto toRead = std::min<IncFsSize>(remaining, capacity - size);
497 buffer->resize(size + toRead);
498 auto read = ::read(incomingFd.get(), buffer->data() + size, toRead);
499 if (read == 0) {
500 if (waitOnEof) {
501 // eof of stdin, waiting...
502 ALOGE("eof of stdin, waiting...: %d, remaining: %d, block: %d, read: %d",
503 int(totalSize), int(remaining), int(blockIdx), int(read));
504 using namespace std::chrono_literals;
505 std::this_thread::sleep_for(10ms);
506 continue;
507 }
508 break;
509 }
510 if (read < 0) {
511 return false;
512 }
513
514 buffer->resize(size + read);
515 remaining -= read;
516 totalSize += read;
517 }
518 if (!buffer->empty() && !flashToIncFs(incfsFd, kind, true, &blockIdx, buffer, blocks)) {
519 return false;
520 }
521 return true;
522 }
523
524 bool flashToIncFs(borrowed_fd incfsFd, IncFsBlockKind kind, bool eof, IncFsBlockIndex* blockIdx,
525 std::vector<char>* buffer, std::vector<IncFsDataBlock>* blocks) {
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800526 int consumed = 0;
527 const auto fullBlocks = buffer->size() / INCFS_DATA_FILE_BLOCK_SIZE;
528 for (int i = 0; i < fullBlocks; ++i) {
529 const auto inst = IncFsDataBlock{
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800530 .fileFd = incfsFd.get(),
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800531 .pageIndex = (*blockIdx)++,
532 .compression = INCFS_COMPRESSION_KIND_NONE,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800533 .kind = kind,
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800534 .dataSize = INCFS_DATA_FILE_BLOCK_SIZE,
535 .data = buffer->data() + consumed,
536 };
537 blocks->push_back(inst);
538 consumed += INCFS_DATA_FILE_BLOCK_SIZE;
539 }
540 const auto remain = buffer->size() - fullBlocks * INCFS_DATA_FILE_BLOCK_SIZE;
541 if (remain && eof) {
542 const auto inst = IncFsDataBlock{
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800543 .fileFd = incfsFd.get(),
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800544 .pageIndex = (*blockIdx)++,
545 .compression = INCFS_COMPRESSION_KIND_NONE,
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800546 .kind = kind,
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800547 .dataSize = static_cast<uint16_t>(remain),
548 .data = buffer->data() + consumed,
549 };
550 blocks->push_back(inst);
551 consumed += remain;
552 }
553
Songchun Fan9b753082020-02-26 13:08:06 -0800554 auto res = mIfs->writeBlocks({blocks->data(), blocks->size()});
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800555
556 blocks->clear();
557 buffer->erase(buffer->begin(), buffer->begin() + consumed);
558
559 if (res < 0) {
560 ALOGE("Failed to write block to IncFS: %d", int(res));
561 return false;
562 }
563 return true;
564 }
565
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800566 // Read tracing.
567 struct TracedRead {
568 uint64_t timestampUs;
569 android::dataloader::FileId fileId;
570 uint32_t firstBlockIdx;
571 uint32_t count;
572 };
573
Songchun Fan9b753082020-02-26 13:08:06 -0800574 void onPageReads(android::dataloader::PageReads pageReads) final {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800575 auto trace = atrace_is_tag_enabled(ATRACE_TAG);
576 if (CC_LIKELY(!trace)) {
577 return;
578 }
579
580 TracedRead last = {};
581 for (auto&& read : pageReads) {
582 if (read.id != last.fileId || read.block != last.firstBlockIdx + last.count) {
583 traceRead(last);
584 last = TracedRead{
585 .timestampUs = read.bootClockTsUs,
586 .fileId = read.id,
587 .firstBlockIdx = (uint32_t)read.block,
588 .count = 1,
589 };
590 } else {
591 ++last.count;
592 }
593 }
594 traceRead(last);
595 }
596
597 void traceRead(const TracedRead& read) {
598 if (!read.count) {
599 return;
600 }
601
602 FileIdx fileIdx = convertFileIdToFileIndex(read.fileId);
603 auto str = android::base::StringPrintf("page_read: index=%lld count=%lld file=%d",
604 static_cast<long long>(read.firstBlockIdx),
605 static_cast<long long>(read.count),
606 static_cast<int>(fileIdx));
607 ATRACE_BEGIN(str.c_str());
608 ATRACE_END();
609 }
610
611 // Streaming.
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700612 bool initStreaming(unique_fd inout, MetadataMode mode) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800613 mEventFd.reset(eventfd(0, EFD_CLOEXEC));
614 if (mEventFd < 0) {
615 ALOGE("Failed to create eventfd.");
616 return false;
617 }
618
619 // Awaiting adb handshake.
620 char okay_buf[OKAY.size()];
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700621 if (!android::base::ReadFully(inout, okay_buf, OKAY.size())) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800622 ALOGE("Failed to receive OKAY. Abort.");
623 return false;
624 }
625 if (std::string_view(okay_buf, OKAY.size()) != OKAY) {
626 ALOGE("Received '%.*s', expecting '%.*s'", (int)OKAY.size(), okay_buf, (int)OKAY.size(),
627 OKAY.data());
628 return false;
629 }
630
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700631 {
632 std::lock_guard lock{mOutFdLock};
633 mOutFd.reset(::dup(inout));
634 if (mOutFd < 0) {
635 ALOGE("Failed to create streaming fd.");
636 }
637 }
638
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700639 mReceiverThread = std::thread(
640 [this, io = std::move(inout), mode]() mutable { receiver(std::move(io), mode); });
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800641 ALOGI("Started streaming...");
642 return true;
643 }
644
645 // IFS callbacks.
Songchun Fan9b753082020-02-26 13:08:06 -0800646 void onPendingReads(dataloader::PendingReads pendingReads) final {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700647 std::lock_guard lock{mOutFdLock};
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700648 if (mOutFd < 0) {
649 return;
650 }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800651 CHECK(mIfs);
652 for (auto&& pendingRead : pendingReads) {
653 const android::dataloader::FileId& fileId = pendingRead.id;
654 const auto blockIdx = static_cast<BlockIdx>(pendingRead.block);
655 /*
656 ALOGI("Missing: %d", (int) blockIdx);
657 */
658 FileIdx fileIdx = convertFileIdToFileIndex(fileId);
659 if (fileIdx < 0) {
660 ALOGE("Failed to handle event for fileid=%s. Ignore.",
661 android::incfs::toString(fileId).c_str());
662 continue;
663 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700664 if (mRequestedFiles.insert(fileIdx).second &&
665 !sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
666 mRequestedFiles.erase(fileIdx);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800667 }
668 sendRequest(mOutFd, BLOCK_MISSING, fileIdx, blockIdx);
669 }
670 }
671
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700672 void receiver(unique_fd inout, MetadataMode mode) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800673 std::vector<uint8_t> data;
674 std::vector<IncFsDataBlock> instructions;
675 std::unordered_map<FileIdx, unique_fd> writeFds;
676 while (!mStopReceiving) {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700677 const int res = waitForDataOrSignal(inout, mEventFd);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800678 if (res == 0) {
679 continue;
680 }
681 if (res < 0) {
682 ALOGE("Failed to poll. Abort.");
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700683 mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800684 break;
685 }
686 if (res == mEventFd) {
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700687 ALOGE("Received stop signal. Sending EXIT to server.");
688 sendRequest(inout, EXIT);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800689 break;
690 }
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700691 if (!readChunk(inout, data)) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800692 ALOGE("Failed to read a message. Abort.");
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -0700693 mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800694 break;
695 }
696 auto remainingData = std::span(data);
697 while (!remainingData.empty()) {
698 auto header = readHeader(remainingData);
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700699 if (header.fileIdx == -1 && header.blockType == 0 && header.compressionType == 0 &&
700 header.blockIdx == 0 && header.blockSize == 0) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800701 ALOGI("Stop signal received. Sending exit command (remaining bytes: %d).",
702 int(remainingData.size()));
703
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700704 sendRequest(inout, EXIT);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800705 mStopReceiving = true;
706 break;
707 }
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700708 if (header.fileIdx < 0 || header.blockSize <= 0 || header.blockType < 0 ||
709 header.compressionType < 0 || header.blockIdx < 0) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800710 ALOGE("invalid header received. Abort.");
711 mStopReceiving = true;
712 break;
713 }
714 const FileIdx fileIdx = header.fileIdx;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700715 const android::dataloader::FileId fileId = convertFileIndexToFileId(mode, fileIdx);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800716 if (!android::incfs::isValidFileId(fileId)) {
717 ALOGE("Unknown data destination for file ID %d. "
718 "Ignore.",
719 header.fileIdx);
720 continue;
721 }
722
723 auto& writeFd = writeFds[fileIdx];
724 if (writeFd < 0) {
Yurii Zubrytskyie82cdd72020-04-01 12:19:26 -0700725 writeFd.reset(this->mIfs->openForSpecialOps(fileId).release());
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800726 if (writeFd < 0) {
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700727 ALOGE("Failed to open file %d for writing (%d). Aborting.", header.fileIdx,
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800728 -writeFd);
729 break;
730 }
731 }
732
733 const auto inst = IncFsDataBlock{
734 .fileFd = writeFd,
735 .pageIndex = static_cast<IncFsBlockIndex>(header.blockIdx),
736 .compression = static_cast<IncFsCompressionKind>(header.compressionType),
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700737 .kind = static_cast<IncFsBlockKind>(header.blockType),
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800738 .dataSize = static_cast<uint16_t>(header.blockSize),
739 .data = (const char*)remainingData.data(),
740 };
741 instructions.push_back(inst);
742 remainingData = remainingData.subspan(header.blockSize);
743 }
744 writeInstructions(instructions);
745 }
746 writeInstructions(instructions);
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700747
748 {
749 std::lock_guard lock{mOutFdLock};
750 mOutFd.reset();
751 }
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800752 }
753
754 void writeInstructions(std::vector<IncFsDataBlock>& instructions) {
755 auto res = this->mIfs->writeBlocks(instructions);
756 if (res != instructions.size()) {
757 ALOGE("Dailed to write data to Incfs (res=%d when expecting %d)", res,
758 int(instructions.size()));
759 }
760 instructions.clear();
761 }
762
763 FileIdx convertFileIdToFileIndex(android::dataloader::FileId fileId) {
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700764 // FileId has format '\2FileIdx'.
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800765 const char* meta = (const char*)&fileId;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700766
767 int8_t mode = *meta;
768 if (mode != DATA_ONLY_STREAMING && mode != STREAMING) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800769 return -1;
770 }
771
772 int fileIdx;
773 auto res = std::from_chars(meta + 1, meta + sizeof(fileId), fileIdx);
774 if (res.ec != std::errc{} || fileIdx < std::numeric_limits<FileIdx>::min() ||
775 fileIdx > std::numeric_limits<FileIdx>::max()) {
776 return -1;
777 }
778
779 return FileIdx(fileIdx);
780 }
781
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700782 android::dataloader::FileId convertFileIndexToFileId(MetadataMode mode, FileIdx fileIdx) {
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800783 IncFsFileId fileId = {};
784 char* meta = (char*)&fileId;
Alex Buynytskyy06970b92020-03-25 12:50:10 -0700785 *meta = mode;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800786 if (auto [p, ec] = std::to_chars(meta + 1, meta + sizeof(fileId), fileIdx);
787 ec != std::errc()) {
788 return {};
789 }
790 return fileId;
791 }
792
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800793 JavaVM* const mJvm;
794 std::string mArgs;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800795 android::dataloader::FilesystemConnectorPtr mIfs = nullptr;
796 android::dataloader::StatusListenerPtr mStatusListener = nullptr;
Alex Buynytskyy606e4f52020-03-13 17:25:37 -0700797 std::mutex mOutFdLock;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800798 android::base::unique_fd mOutFd;
799 android::base::unique_fd mEventFd;
800 std::thread mReceiverThread;
801 std::atomic<bool> mStopReceiving = false;
Alex Buynytskyy74247b92020-05-12 17:14:09 -0700802 std::atomic<bool> mReadLogsEnabled = false;
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800803 /** Tracks which files have been requested */
804 std::unordered_set<FileIdx> mRequestedFiles;
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800805};
806
Alex Buynytskyy74247b92020-05-12 17:14:09 -0700807OnTraceChanged::OnTraceChanged() {
808 mChecker = std::thread([this]() {
809 bool oldTrace = atrace_is_tag_enabled(ATRACE_TAG);
810 while (mRunning) {
811 bool newTrace = atrace_is_tag_enabled(ATRACE_TAG);
812 if (oldTrace != newTrace) {
813 std::unique_lock lock(mMutex);
814 for (auto&& callback : mCallbacks) {
815 callback->updateReadLogsState(newTrace);
816 }
817 }
818 oldTrace = newTrace;
819 std::this_thread::sleep_for(TraceTagCheckInterval);
820 }
821 });
822}
823
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800824BlockHeader readHeader(std::span<uint8_t>& data) {
825 BlockHeader header;
826 if (data.size() < sizeof(header)) {
827 return header;
828 }
829
830 header.fileIdx = static_cast<FileIdx>(be16toh(*reinterpret_cast<const uint16_t*>(&data[0])));
Alex Buynytskyye9d20f02020-03-20 10:45:51 -0700831 header.blockType = static_cast<BlockType>(data[2]);
832 header.compressionType = static_cast<CompressionType>(data[3]);
Alex Buynytskyy17d9da02020-02-12 16:03:30 -0800833 header.blockIdx = static_cast<BlockIdx>(be32toh(*reinterpret_cast<const uint32_t*>(&data[4])));
834 header.blockSize =
835 static_cast<BlockSize>(be16toh(*reinterpret_cast<const uint16_t*>(&data[8])));
836 data = data.subspan(sizeof(header));
837
838 return header;
839}
840
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800841static void nativeInitialize(JNIEnv* env, jclass klass) {
842 jniIds(env);
843}
844
845static const JNINativeMethod method_table[] = {
846 {"nativeInitialize", "()V", (void*)nativeInitialize},
847};
848
849} // namespace
850
851int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(
852 JNIEnv* env) {
853 android::dataloader::DataLoader::initialize(
854 [](auto jvm, const auto& params) -> android::dataloader::DataLoaderPtr {
855 if (params.type() == DATA_LOADER_TYPE_INCREMENTAL) {
856 // This DataLoader only supports incremental installations.
Alex Buynytskyy74247b92020-05-12 17:14:09 -0700857 return std::make_unique<PMSCDataLoader>(jvm);
Alex Buynytskyy04f73912020-02-10 08:34:18 -0800858 }
859 return {};
860 });
861 return jniRegisterNativeMethods(env,
862 "com/android/server/pm/PackageManagerShellCommandDataLoader",
863 method_table, NELEM(method_table));
864}
865
866} // namespace android