1*33f37583SAndroid Build Coastguard Worker /*
2*33f37583SAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*33f37583SAndroid Build Coastguard Worker *
4*33f37583SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*33f37583SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*33f37583SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*33f37583SAndroid Build Coastguard Worker *
8*33f37583SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*33f37583SAndroid Build Coastguard Worker *
10*33f37583SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*33f37583SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*33f37583SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*33f37583SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*33f37583SAndroid Build Coastguard Worker * limitations under the License.
15*33f37583SAndroid Build Coastguard Worker */
16*33f37583SAndroid Build Coastguard Worker
17*33f37583SAndroid Build Coastguard Worker #include "apex_classpath.h"
18*33f37583SAndroid Build Coastguard Worker
19*33f37583SAndroid Build Coastguard Worker #include <android-base/file.h>
20*33f37583SAndroid Build Coastguard Worker #include <android-base/scopeguard.h>
21*33f37583SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
22*33f37583SAndroid Build Coastguard Worker #include <android-base/strings.h>
23*33f37583SAndroid Build Coastguard Worker #include <logwrap/logwrap.h>
24*33f37583SAndroid Build Coastguard Worker
25*33f37583SAndroid Build Coastguard Worker #include <fstream>
26*33f37583SAndroid Build Coastguard Worker #include <regex>
27*33f37583SAndroid Build Coastguard Worker
28*33f37583SAndroid Build Coastguard Worker namespace android {
29*33f37583SAndroid Build Coastguard Worker namespace apex {
30*33f37583SAndroid Build Coastguard Worker
31*33f37583SAndroid Build Coastguard Worker using ::android::base::Error;
32*33f37583SAndroid Build Coastguard Worker using ::android::base::StringPrintf;
33*33f37583SAndroid Build Coastguard Worker
DeriveClassPath(const std::vector<std::string> & temp_mounted_apex_paths,const std::string & sdkext_module_name)34*33f37583SAndroid Build Coastguard Worker android::base::Result<ClassPath> ClassPath::DeriveClassPath(
35*33f37583SAndroid Build Coastguard Worker const std::vector<std::string>& temp_mounted_apex_paths,
36*33f37583SAndroid Build Coastguard Worker const std::string& sdkext_module_name) {
37*33f37583SAndroid Build Coastguard Worker if (temp_mounted_apex_paths.empty()) {
38*33f37583SAndroid Build Coastguard Worker return Error()
39*33f37583SAndroid Build Coastguard Worker << "Invalid argument: There are no APEX to derive claspath from";
40*33f37583SAndroid Build Coastguard Worker }
41*33f37583SAndroid Build Coastguard Worker // Call derive_classpath binary to generate required information
42*33f37583SAndroid Build Coastguard Worker
43*33f37583SAndroid Build Coastguard Worker // Prefer using the binary from staged session if possible
44*33f37583SAndroid Build Coastguard Worker std::string apex_of_binary =
45*33f37583SAndroid Build Coastguard Worker StringPrintf("/apex/%s", sdkext_module_name.c_str());
46*33f37583SAndroid Build Coastguard Worker for (const auto& temp_mounted_apex_path : temp_mounted_apex_paths) {
47*33f37583SAndroid Build Coastguard Worker if (temp_mounted_apex_path.starts_with(apex_of_binary + "@")) {
48*33f37583SAndroid Build Coastguard Worker apex_of_binary = temp_mounted_apex_path;
49*33f37583SAndroid Build Coastguard Worker break;
50*33f37583SAndroid Build Coastguard Worker }
51*33f37583SAndroid Build Coastguard Worker }
52*33f37583SAndroid Build Coastguard Worker std::string binary_path =
53*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/bin/derive_classpath", apex_of_binary.c_str());
54*33f37583SAndroid Build Coastguard Worker std::string scan_dirs_flag =
55*33f37583SAndroid Build Coastguard Worker StringPrintf("--scan-dirs=%s",
56*33f37583SAndroid Build Coastguard Worker android::base::Join(temp_mounted_apex_paths, ",").c_str());
57*33f37583SAndroid Build Coastguard Worker
58*33f37583SAndroid Build Coastguard Worker // Create a temp file to write output
59*33f37583SAndroid Build Coastguard Worker auto temp_output_path = "/apex/derive_classpath_temp";
60*33f37583SAndroid Build Coastguard Worker auto cleanup = [temp_output_path]() {
61*33f37583SAndroid Build Coastguard Worker android::base::RemoveFileIfExists(temp_output_path);
62*33f37583SAndroid Build Coastguard Worker };
63*33f37583SAndroid Build Coastguard Worker auto scope_guard = android::base::make_scope_guard(cleanup);
64*33f37583SAndroid Build Coastguard Worker // Cleanup to ensure we are creating an empty file
65*33f37583SAndroid Build Coastguard Worker cleanup();
66*33f37583SAndroid Build Coastguard Worker // Create the empty file where derive_classpath will write into
67*33f37583SAndroid Build Coastguard Worker std::ofstream _(temp_output_path);
68*33f37583SAndroid Build Coastguard Worker
69*33f37583SAndroid Build Coastguard Worker const char* const argv[] = {binary_path.c_str(), scan_dirs_flag.c_str(),
70*33f37583SAndroid Build Coastguard Worker temp_output_path};
71*33f37583SAndroid Build Coastguard Worker auto rc = logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG,
72*33f37583SAndroid Build Coastguard Worker false, nullptr);
73*33f37583SAndroid Build Coastguard Worker if (rc != 0) {
74*33f37583SAndroid Build Coastguard Worker return Error() << "Running derive_classpath failed; binary path: " +
75*33f37583SAndroid Build Coastguard Worker binary_path;
76*33f37583SAndroid Build Coastguard Worker }
77*33f37583SAndroid Build Coastguard Worker
78*33f37583SAndroid Build Coastguard Worker return ClassPath::ParseFromFile(temp_output_path);
79*33f37583SAndroid Build Coastguard Worker }
80*33f37583SAndroid Build Coastguard Worker
81*33f37583SAndroid Build Coastguard Worker // Parse the string output into structured information
82*33f37583SAndroid Build Coastguard Worker // The raw output from derive_classpath has the following format:
83*33f37583SAndroid Build Coastguard Worker // ```
84*33f37583SAndroid Build Coastguard Worker // export BOOTCLASSPATH path/to/jar1:/path/to/jar2
85*33f37583SAndroid Build Coastguard Worker // export DEX2OATBOOTCLASSPATH
86*33f37583SAndroid Build Coastguard Worker // export SYSTEMSERVERCLASSPATH path/to/some/jar
ParseFromFile(const std::string & file_path)87*33f37583SAndroid Build Coastguard Worker android::base::Result<ClassPath> ClassPath::ParseFromFile(
88*33f37583SAndroid Build Coastguard Worker const std::string& file_path) {
89*33f37583SAndroid Build Coastguard Worker ClassPath result;
90*33f37583SAndroid Build Coastguard Worker
91*33f37583SAndroid Build Coastguard Worker std::string contents;
92*33f37583SAndroid Build Coastguard Worker auto read_status = android::base::ReadFileToString(file_path, &contents,
93*33f37583SAndroid Build Coastguard Worker /*follow_symlinks=*/false);
94*33f37583SAndroid Build Coastguard Worker if (!read_status) {
95*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to read classpath info from file";
96*33f37583SAndroid Build Coastguard Worker }
97*33f37583SAndroid Build Coastguard Worker
98*33f37583SAndroid Build Coastguard Worker // Jars in apex have the following format: /apex/<package-name>/*
99*33f37583SAndroid Build Coastguard Worker const std::regex capture_apex_package_name("^/apex/([^/]+)/");
100*33f37583SAndroid Build Coastguard Worker
101*33f37583SAndroid Build Coastguard Worker for (const auto& line : android::base::Split(contents, "\n")) {
102*33f37583SAndroid Build Coastguard Worker // Split the line by space. The second element determines which type of
103*33f37583SAndroid Build Coastguard Worker // classpath we are dealing with and the third element are the jars
104*33f37583SAndroid Build Coastguard Worker // separated by :
105*33f37583SAndroid Build Coastguard Worker auto tokens = android::base::Split(line, " ");
106*33f37583SAndroid Build Coastguard Worker if (tokens.size() < 3) {
107*33f37583SAndroid Build Coastguard Worker continue;
108*33f37583SAndroid Build Coastguard Worker }
109*33f37583SAndroid Build Coastguard Worker auto jars_list = tokens[2];
110*33f37583SAndroid Build Coastguard Worker for (const auto& jar_path : android::base::Split(jars_list, ":")) {
111*33f37583SAndroid Build Coastguard Worker std::smatch match;
112*33f37583SAndroid Build Coastguard Worker if (std::regex_search(jar_path, match, capture_apex_package_name)) {
113*33f37583SAndroid Build Coastguard Worker auto package_name = match[1];
114*33f37583SAndroid Build Coastguard Worker result.AddPackageWithClasspathJars(package_name);
115*33f37583SAndroid Build Coastguard Worker }
116*33f37583SAndroid Build Coastguard Worker }
117*33f37583SAndroid Build Coastguard Worker }
118*33f37583SAndroid Build Coastguard Worker return result;
119*33f37583SAndroid Build Coastguard Worker }
120*33f37583SAndroid Build Coastguard Worker
AddPackageWithClasspathJars(const std::string & package)121*33f37583SAndroid Build Coastguard Worker void ClassPath::AddPackageWithClasspathJars(const std::string& package) {
122*33f37583SAndroid Build Coastguard Worker packages_with_classpath_jars.insert(package);
123*33f37583SAndroid Build Coastguard Worker }
124*33f37583SAndroid Build Coastguard Worker
HasClassPathJars(const std::string & package)125*33f37583SAndroid Build Coastguard Worker bool ClassPath::HasClassPathJars(const std::string& package) {
126*33f37583SAndroid Build Coastguard Worker return packages_with_classpath_jars.find(package) !=
127*33f37583SAndroid Build Coastguard Worker packages_with_classpath_jars.end();
128*33f37583SAndroid Build Coastguard Worker }
129*33f37583SAndroid Build Coastguard Worker
130*33f37583SAndroid Build Coastguard Worker } // namespace apex
131*33f37583SAndroid Build Coastguard Worker } // namespace android
132