blob: d3f35c8ef41400e123ae7235f40c49511828682b [file] [log] [blame]
Idries Hamadied409ea2018-01-29 16:30:36 +00001/*
2 * Copyright (C) 2018 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
Idries Hamadied409ea2018-01-29 16:30:36 +000017#include <libgen.h>
18#include <algorithm>
Idries Hamadi5b6bf942018-08-28 12:58:09 +010019#include <array>
Idries Hamadied409ea2018-01-29 16:30:36 +000020
Idries Hamadi5b6bf942018-08-28 12:58:09 +010021#include "android-base/file.h"
22#include "android-base/strings.h"
Idries Hamadied409ea2018-01-29 16:30:36 +000023#include "client/file_sync_client.h"
24#include "commandline.h"
25#include "fastdeploy.h"
26#include "fastdeploycallbacks.h"
27#include "utils/String16.h"
28
Elliott Hughes86ab9ff2018-09-05 12:13:11 -070029static constexpr long kRequiredAgentVersion = 0x00000001;
Idries Hamadied409ea2018-01-29 16:30:36 +000030
Elliott Hughes86ab9ff2018-09-05 12:13:11 -070031static constexpr const char* kDeviceAgentPath = "/data/local/tmp/";
Idries Hamadied409ea2018-01-29 16:30:36 +000032
Idries Hamadi4af6ee42018-09-06 18:42:39 +010033static bool g_use_localagent = false;
Idries Hamadi5b6bf942018-08-28 12:58:09 +010034
Idries Hamadied409ea2018-01-29 16:30:36 +000035long get_agent_version() {
36 std::vector<char> versionOutputBuffer;
37 std::vector<char> versionErrorBuffer;
38
Idries Hamadi7575cd92018-08-24 11:46:45 +010039 int statusCode = capture_shell_command("/data/local/tmp/deployagent version",
Idries Hamadied409ea2018-01-29 16:30:36 +000040 &versionOutputBuffer, &versionErrorBuffer);
41 long version = -1;
42
43 if (statusCode == 0 && versionOutputBuffer.size() > 0) {
44 version = strtol((char*)versionOutputBuffer.data(), NULL, 16);
45 }
46
47 return version;
48}
49
50int get_device_api_level() {
51 std::vector<char> sdkVersionOutputBuffer;
52 std::vector<char> sdkVersionErrorBuffer;
53 int api_level = -1;
54
55 int statusCode = capture_shell_command("getprop ro.build.version.sdk", &sdkVersionOutputBuffer,
56 &sdkVersionErrorBuffer);
Idries Hamadi7f51e002018-08-23 17:22:21 +010057 if (statusCode == 0 && sdkVersionOutputBuffer.size() > 0) {
Idries Hamadied409ea2018-01-29 16:30:36 +000058 api_level = strtol((char*)sdkVersionOutputBuffer.data(), NULL, 10);
59 }
60
61 return api_level;
62}
63
Idries Hamadi4af6ee42018-09-06 18:42:39 +010064void fastdeploy_set_local_agent(bool use_localagent) {
65 g_use_localagent = use_localagent;
Idries Hamadi5b6bf942018-08-28 12:58:09 +010066}
67
Idries Hamadied409ea2018-01-29 16:30:36 +000068// local_path - must start with a '/' and be relative to $ANDROID_PRODUCT_OUT
Idries Hamadi4af6ee42018-09-06 18:42:39 +010069static std::string get_agent_component_host_path(const char* local_path, const char* sdk_path) {
Idries Hamadi5b6bf942018-08-28 12:58:09 +010070 std::string adb_dir = android::base::GetExecutableDirectory();
71 if (adb_dir.empty()) {
Idries Hamadi4af6ee42018-09-06 18:42:39 +010072 fatal("Could not determine location of adb!");
Idries Hamadied409ea2018-01-29 16:30:36 +000073 }
74
Idries Hamadi4af6ee42018-09-06 18:42:39 +010075 if (g_use_localagent) {
Idries Hamadied409ea2018-01-29 16:30:36 +000076 const char* product_out = getenv("ANDROID_PRODUCT_OUT");
77 if (product_out == nullptr) {
Idries Hamadi4af6ee42018-09-06 18:42:39 +010078 fatal("Could not locate %s because $ANDROID_PRODUCT_OUT is not defined", local_path);
Idries Hamadied409ea2018-01-29 16:30:36 +000079 }
Idries Hamadi4af6ee42018-09-06 18:42:39 +010080 return android::base::StringPrintf("%s%s", product_out, local_path);
Idries Hamadied409ea2018-01-29 16:30:36 +000081 } else {
Idries Hamadi4af6ee42018-09-06 18:42:39 +010082 return adb_dir + sdk_path;
Idries Hamadied409ea2018-01-29 16:30:36 +000083 }
Idries Hamadied409ea2018-01-29 16:30:36 +000084}
85
Idries Hamadi5b6bf942018-08-28 12:58:09 +010086static bool deploy_agent(bool checkTimeStamps) {
Idries Hamadied409ea2018-01-29 16:30:36 +000087 std::vector<const char*> srcs;
Idries Hamadi4af6ee42018-09-06 18:42:39 +010088 std::string jar_path =
89 get_agent_component_host_path("/system/framework/deployagent.jar", "/deployagent.jar");
90 std::string script_path =
91 get_agent_component_host_path("/system/bin/deployagent", "/deployagent");
92 srcs.push_back(jar_path.c_str());
93 srcs.push_back(script_path.c_str());
Idries Hamadied409ea2018-01-29 16:30:36 +000094
95 if (do_sync_push(srcs, kDeviceAgentPath, checkTimeStamps)) {
96 // on windows the shell script might have lost execute permission
97 // so need to set this explicitly
Idries Hamadi7575cd92018-08-24 11:46:45 +010098 const char* kChmodCommandPattern = "chmod 777 %sdeployagent";
Idries Hamadied409ea2018-01-29 16:30:36 +000099 std::string chmodCommand =
100 android::base::StringPrintf(kChmodCommandPattern, kDeviceAgentPath);
Idries Hamadi7f51e002018-08-23 17:22:21 +0100101 int ret = send_shell_command(chmodCommand);
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100102 if (ret != 0) {
103 fatal("Error executing %s returncode: %d", chmodCommand.c_str(), ret);
104 }
Idries Hamadied409ea2018-01-29 16:30:36 +0000105 } else {
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100106 fatal("Error pushing agent files to device");
Idries Hamadied409ea2018-01-29 16:30:36 +0000107 }
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100108
109 return true;
Idries Hamadied409ea2018-01-29 16:30:36 +0000110}
111
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100112void update_agent(FastDeploy_AgentUpdateStrategy agentUpdateStrategy) {
Idries Hamadied409ea2018-01-29 16:30:36 +0000113 long agent_version = get_agent_version();
114 switch (agentUpdateStrategy) {
115 case FastDeploy_AgentUpdateAlways:
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100116 deploy_agent(false);
Idries Hamadied409ea2018-01-29 16:30:36 +0000117 break;
118 case FastDeploy_AgentUpdateNewerTimeStamp:
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100119 deploy_agent(true);
Idries Hamadied409ea2018-01-29 16:30:36 +0000120 break;
121 case FastDeploy_AgentUpdateDifferentVersion:
122 if (agent_version != kRequiredAgentVersion) {
123 if (agent_version < 0) {
124 printf("Could not detect agent on device, deploying\n");
125 } else {
126 printf("Device agent version is (%ld), (%ld) is required, re-deploying\n",
127 agent_version, kRequiredAgentVersion);
128 }
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100129 deploy_agent(false);
Idries Hamadied409ea2018-01-29 16:30:36 +0000130 }
131 break;
132 }
133
134 agent_version = get_agent_version();
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100135 if (agent_version != kRequiredAgentVersion) {
136 fatal("After update agent version remains incorrect! Expected %ld but version is %ld",
137 kRequiredAgentVersion, agent_version);
138 }
Idries Hamadied409ea2018-01-29 16:30:36 +0000139}
140
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100141static std::string get_aapt2_path() {
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100142 if (g_use_localagent) {
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100143 // This should never happen on a Windows machine
144 const char* host_out = getenv("ANDROID_HOST_OUT");
145 if (host_out == nullptr) {
146 fatal("Could not locate aapt2 because $ANDROID_HOST_OUT is not defined");
147 }
148 return android::base::StringPrintf("%s/bin/aapt2", host_out);
Idries Hamadied409ea2018-01-29 16:30:36 +0000149 }
150
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100151 std::string adb_dir = android::base::GetExecutableDirectory();
152 if (adb_dir.empty()) {
153 fatal("Could not locate aapt2");
154 }
155 return adb_dir + "/aapt2";
156}
157
158static int system_capture(const char* cmd, std::string& output) {
159 FILE* pipe = popen(cmd, "re");
160 int fd = -1;
161
162 if (pipe != nullptr) {
163 fd = fileno(pipe);
164 }
165
166 if (fd == -1) {
167 fatal_errno("Could not create pipe for process '%s'", cmd);
168 }
169
170 if (!android::base::ReadFdToString(fd, &output)) {
171 fatal_errno("Error reading from process '%s'", cmd);
172 }
173
174 return pclose(pipe);
Idries Hamadied409ea2018-01-29 16:30:36 +0000175}
176
177// output is required to point to a valid output string (non-null)
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100178static std::string get_packagename_from_apk(const char* apkPath) {
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100179 const char* kAapt2DumpNameCommandPattern = R"(%s dump packagename "%s")";
180 std::string aapt2_path_string = get_aapt2_path();
181 std::string getPackagenameCommand = android::base::StringPrintf(
182 kAapt2DumpNameCommandPattern, aapt2_path_string.c_str(), apkPath);
Idries Hamadied409ea2018-01-29 16:30:36 +0000183
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100184 std::string package_name;
185 int exit_code = system_capture(getPackagenameCommand.c_str(), package_name);
186 if (exit_code != 0) {
187 fatal("Error executing '%s' exitcode: %d", getPackagenameCommand.c_str(), exit_code);
Idries Hamadied409ea2018-01-29 16:30:36 +0000188 }
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100189
190 // strip any line end characters from the output
191 return android::base::Trim(package_name);
Idries Hamadied409ea2018-01-29 16:30:36 +0000192}
193
194int extract_metadata(const char* apkPath, FILE* outputFp) {
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100195 std::string packageName = get_packagename_from_apk(apkPath);
Idries Hamadi7575cd92018-08-24 11:46:45 +0100196 const char* kAgentExtractCommandPattern = "/data/local/tmp/deployagent extract %s";
Idries Hamadied409ea2018-01-29 16:30:36 +0000197 std::string extractCommand =
198 android::base::StringPrintf(kAgentExtractCommandPattern, packageName.c_str());
199
200 std::vector<char> extractErrorBuffer;
201 int statusCode;
202 DeployAgentFileCallback cb(outputFp, &extractErrorBuffer, &statusCode);
Idries Hamadi7f51e002018-08-23 17:22:21 +0100203 int ret = send_shell_command(extractCommand, false, &cb);
Idries Hamadied409ea2018-01-29 16:30:36 +0000204
205 if (ret == 0) {
206 return cb.getBytesWritten();
207 }
208
209 return ret;
210}
211
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100212static std::string get_patch_generator_command() {
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100213 if (g_use_localagent) {
Idries Hamadied409ea2018-01-29 16:30:36 +0000214 // This should never happen on a Windows machine
Idries Hamadied409ea2018-01-29 16:30:36 +0000215 const char* host_out = getenv("ANDROID_HOST_OUT");
216 if (host_out == nullptr) {
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100217 fatal("Could not locate deploypatchgenerator.jar because $ANDROID_HOST_OUT is not "
218 "defined");
Idries Hamadied409ea2018-01-29 16:30:36 +0000219 }
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100220 return android::base::StringPrintf("java -jar %s/framework/deploypatchgenerator.jar",
221 host_out);
Idries Hamadied409ea2018-01-29 16:30:36 +0000222 }
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100223
224 std::string adb_dir = android::base::GetExecutableDirectory();
225 if (adb_dir.empty()) {
226 fatal("Could not locate deploypatchgenerator.jar");
227 }
228 return android::base::StringPrintf(R"(java -jar "%s/deploypatchgenerator.jar")",
229 adb_dir.c_str());
Idries Hamadied409ea2018-01-29 16:30:36 +0000230}
231
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100232int create_patch(const char* apkPath, const char* metadataPath, const char* patchPath) {
Idries Hamadied409ea2018-01-29 16:30:36 +0000233 std::string generatePatchCommand = android::base::StringPrintf(
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100234 R"(%s "%s" "%s" > "%s")", get_patch_generator_command().c_str(), apkPath, metadataPath,
235 patchPath);
Idries Hamadied409ea2018-01-29 16:30:36 +0000236 return system(generatePatchCommand.c_str());
237}
238
239std::string get_patch_path(const char* apkPath) {
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100240 std::string packageName = get_packagename_from_apk(apkPath);
Idries Hamadied409ea2018-01-29 16:30:36 +0000241 std::string patchDevicePath =
242 android::base::StringPrintf("%s%s.patch", kDeviceAgentPath, packageName.c_str());
243 return patchDevicePath;
244}
245
246int apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath) {
Idries Hamadi7575cd92018-08-24 11:46:45 +0100247 const std::string kAgentApplyCommandPattern = "/data/local/tmp/deployagent apply %s %s -o %s";
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100248 std::string packageName = get_packagename_from_apk(apkPath);
Idries Hamadied409ea2018-01-29 16:30:36 +0000249 std::string patchDevicePath = get_patch_path(apkPath);
250
251 std::vector<const char*> srcs = {patchPath};
252 bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
253
254 if (!push_ok) {
255 return -1;
256 }
257
258 std::string applyPatchCommand =
259 android::base::StringPrintf(kAgentApplyCommandPattern.c_str(), packageName.c_str(),
260 patchDevicePath.c_str(), outputPath);
Idries Hamadi5b6bf942018-08-28 12:58:09 +0100261
Idries Hamadied409ea2018-01-29 16:30:36 +0000262 return send_shell_command(applyPatchCommand);
263}
264
265int install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv) {
Idries Hamadi7575cd92018-08-24 11:46:45 +0100266 const std::string kAgentApplyCommandPattern = "/data/local/tmp/deployagent apply %s %s -pm %s";
Idries Hamadi4af6ee42018-09-06 18:42:39 +0100267 std::string packageName = get_packagename_from_apk(apkPath);
Idries Hamadied409ea2018-01-29 16:30:36 +0000268 std::vector<const char*> srcs;
269 std::string patchDevicePath =
270 android::base::StringPrintf("%s%s.patch", kDeviceAgentPath, packageName.c_str());
271 srcs.push_back(patchPath);
272 bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
273
274 if (!push_ok) {
275 return -1;
276 }
277
278 std::vector<unsigned char> applyOutputBuffer;
279 std::vector<unsigned char> applyErrorBuffer;
280 std::string argsString;
281
282 for (int i = 0; i < argc; i++) {
283 argsString.append(argv[i]);
284 argsString.append(" ");
285 }
286
287 std::string applyPatchCommand =
288 android::base::StringPrintf(kAgentApplyCommandPattern.c_str(), packageName.c_str(),
289 patchDevicePath.c_str(), argsString.c_str());
290 return send_shell_command(applyPatchCommand);
291}