1 /* 2 * Copyright (C) 2019 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 #include "patch_utils.h" 18 19 #include <stdio.h> 20 21 #include "adb_io.h" 22 #include "adb_utils.h" 23 #include "android-base/endian.h" 24 #include "sysdeps.h" 25 26 #include "apk_archive.h" 27 28 using namespace com::android; 29 using namespace com::android::fastdeploy; 30 using namespace android::base; 31 32 static constexpr char kSignature[] = "FASTDEPLOY"; 33 34 APKMetaData PatchUtils::GetDeviceAPKMetaData(const APKDump& apk_dump) { 35 APKMetaData apkMetaData; 36 apkMetaData.set_absolute_path(apk_dump.absolute_path()); 37 38 std::string md5Hash; 39 int64_t localFileHeaderOffset; 40 int64_t dataSize; 41 42 const auto& cd = apk_dump.cd(); 43 auto cur = cd.data(); 44 int64_t size = cd.size(); 45 while (auto consumed = ApkArchive::ParseCentralDirectoryRecord( 46 cur, size, &md5Hash, &localFileHeaderOffset, &dataSize)) { 47 cur += consumed; 48 size -= consumed; 49 50 auto apkEntry = apkMetaData.add_entries(); 51 apkEntry->set_md5(md5Hash); 52 apkEntry->set_dataoffset(localFileHeaderOffset); 53 apkEntry->set_datasize(dataSize); 54 } 55 return apkMetaData; 56 } 57 58 APKMetaData PatchUtils::GetHostAPKMetaData(const char* apkPath) { 59 ApkArchive archive(apkPath); 60 auto dump = archive.ExtractMetadata(); 61 if (dump.cd().empty()) { 62 fprintf(stderr, "adb: Could not extract Central Directory from %s\n", apkPath); 63 error_exit("Aborting"); 64 } 65 66 auto apkMetaData = GetDeviceAPKMetaData(dump); 67 68 // Now let's set data sizes. 69 for (auto& apkEntry : *apkMetaData.mutable_entries()) { 70 auto dataSize = 71 archive.CalculateLocalFileEntrySize(apkEntry.dataoffset(), apkEntry.datasize()); 72 if (dataSize == 0) { 73 error_exit("Aborting"); 74 } 75 apkEntry.set_datasize(dataSize); 76 } 77 78 return apkMetaData; 79 } 80 81 void PatchUtils::WriteSignature(borrowed_fd output) { 82 WriteFdExactly(output, kSignature, sizeof(kSignature) - 1); 83 } 84 85 void PatchUtils::WriteLong(int64_t value, borrowed_fd output) { 86 int64_t littleEndian = htole64(value); 87 WriteFdExactly(output, &littleEndian, sizeof(littleEndian)); 88 } 89 90 void PatchUtils::WriteString(const std::string& value, android::base::borrowed_fd output) { 91 WriteLong(value.size(), output); 92 WriteFdExactly(output, value); 93 } 94 95 void PatchUtils::Pipe(borrowed_fd input, borrowed_fd output, size_t amount) { 96 constexpr static size_t BUFFER_SIZE = 128 * 1024; 97 char buffer[BUFFER_SIZE]; 98 size_t transferAmount = 0; 99 while (transferAmount != amount) { 100 auto chunkAmount = std::min(amount - transferAmount, BUFFER_SIZE); 101 auto readAmount = adb_read(input, buffer, chunkAmount); 102 if (readAmount < 0) { 103 fprintf(stderr, "adb: failed to read from input: %s\n", strerror(errno)); 104 error_exit("Aborting"); 105 } 106 WriteFdExactly(output, buffer, readAmount); 107 transferAmount += readAmount; 108 } 109 } 110