xref: /aosp_15_r20/system/apex/apexd/apex_classpath.cpp (revision 33f3758387333dbd2962d7edbd98681940d895da)
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