xref: /aosp_15_r20/system/extras/preopt2cachename/preopt2cachename.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include <iostream>
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
20*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
21*288bf522SAndroid Build Coastguard Worker 
22*288bf522SAndroid Build Coastguard Worker #ifndef LOG_TAG
23*288bf522SAndroid Build Coastguard Worker #define LOG_TAG "preopt2cachename"
24*288bf522SAndroid Build Coastguard Worker #endif
25*288bf522SAndroid Build Coastguard Worker 
26*288bf522SAndroid Build Coastguard Worker static const char* kDalvikCacheDir = "/data/dalvik-cache/";
27*288bf522SAndroid Build Coastguard Worker static const char* kOdexCacheSuffix = "@classes.dex";
28*288bf522SAndroid Build Coastguard Worker static const char* kVdexCacheSuffix = "@classes.vdex";
29*288bf522SAndroid Build Coastguard Worker static const char* kArtCacheSuffix = "@classes.art";
30*288bf522SAndroid Build Coastguard Worker 
31*288bf522SAndroid Build Coastguard Worker // Returns the ISA extracted from the file_location. file_location is formatted like
32*288bf522SAndroid Build Coastguard Worker // /system{/product,}/{priv-,}app/<app_name>/oat/<isa>/<app_name>.{odex,vdex} for all functions. We
33*288bf522SAndroid Build Coastguard Worker // return an empty string "" in error cases.
ExtractISA(const std::string & file_location)34*288bf522SAndroid Build Coastguard Worker static std::string ExtractISA(const std::string& file_location) {
35*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> split_file_location = android::base::Split(file_location, "/");
36*288bf522SAndroid Build Coastguard Worker   if (split_file_location.size() <= 1) {
37*288bf522SAndroid Build Coastguard Worker     return "";
38*288bf522SAndroid Build Coastguard Worker   } else if (split_file_location.size() != 7 && split_file_location.size() != 8) {
39*288bf522SAndroid Build Coastguard Worker     LOG(WARNING) << "Unexpected length for file-location. We expected 7 or 8 segments but found "
40*288bf522SAndroid Build Coastguard Worker                  << split_file_location.size() << " for " << file_location;
41*288bf522SAndroid Build Coastguard Worker   }
42*288bf522SAndroid Build Coastguard Worker   return split_file_location[split_file_location.size() - 2];
43*288bf522SAndroid Build Coastguard Worker }
44*288bf522SAndroid Build Coastguard Worker 
45*288bf522SAndroid Build Coastguard Worker // Returns the apk name extracted from the file_location.
46*288bf522SAndroid Build Coastguard Worker // file_location is formatted like /system/app/<app_name>/oat/<isa>/<app_name>.{odex,vdex}.
47*288bf522SAndroid Build Coastguard Worker // We return the final <app_name> with the .{odex,vdex} replaced with .apk.
ExtractAPKName(const std::string & file_location)48*288bf522SAndroid Build Coastguard Worker static std::string ExtractAPKName(const std::string& file_location) {
49*288bf522SAndroid Build Coastguard Worker   // Find and copy filename.
50*288bf522SAndroid Build Coastguard Worker   size_t file_location_start = file_location.rfind('/');
51*288bf522SAndroid Build Coastguard Worker   if (file_location_start == std::string::npos) {
52*288bf522SAndroid Build Coastguard Worker     return "";
53*288bf522SAndroid Build Coastguard Worker   }
54*288bf522SAndroid Build Coastguard Worker   size_t ext_start = file_location.rfind('.');
55*288bf522SAndroid Build Coastguard Worker   if (ext_start == std::string::npos || ext_start < file_location_start) {
56*288bf522SAndroid Build Coastguard Worker     return "";
57*288bf522SAndroid Build Coastguard Worker   }
58*288bf522SAndroid Build Coastguard Worker   std::string apk_name = file_location.substr(file_location_start + 1,
59*288bf522SAndroid Build Coastguard Worker                                               ext_start - file_location_start);
60*288bf522SAndroid Build Coastguard Worker 
61*288bf522SAndroid Build Coastguard Worker   // Replace extension with .apk.
62*288bf522SAndroid Build Coastguard Worker   apk_name += "apk";
63*288bf522SAndroid Build Coastguard Worker   return apk_name;
64*288bf522SAndroid Build Coastguard Worker }
65*288bf522SAndroid Build Coastguard Worker 
66*288bf522SAndroid Build Coastguard Worker // The cache file name is /data/dalvik-cache/<isa>/ prior to this function
SystemBFilenameToCacheFile(const std::string & file_location,std::string & cache_file)67*288bf522SAndroid Build Coastguard Worker static bool SystemBFilenameToCacheFile(const std::string& file_location,
68*288bf522SAndroid Build Coastguard Worker                                        /*in-out*/std::string& cache_file) {
69*288bf522SAndroid Build Coastguard Worker   // Skip the first '/' in file_location.
70*288bf522SAndroid Build Coastguard Worker   size_t initial_position = file_location[0] == '/' ? 1 : 0;
71*288bf522SAndroid Build Coastguard Worker   size_t apk_position = file_location.find("/oat", initial_position);
72*288bf522SAndroid Build Coastguard Worker   if (apk_position == std::string::npos) {
73*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to find oat directory!";
74*288bf522SAndroid Build Coastguard Worker     return false;
75*288bf522SAndroid Build Coastguard Worker   }
76*288bf522SAndroid Build Coastguard Worker 
77*288bf522SAndroid Build Coastguard Worker   size_t cache_file_position = cache_file.size();
78*288bf522SAndroid Build Coastguard Worker   cache_file += file_location.substr(initial_position, apk_position);
79*288bf522SAndroid Build Coastguard Worker   // '/' -> '@' up to where the apk would be.
80*288bf522SAndroid Build Coastguard Worker   cache_file_position = cache_file.find('/', cache_file_position);
81*288bf522SAndroid Build Coastguard Worker   while (cache_file_position != std::string::npos) {
82*288bf522SAndroid Build Coastguard Worker     cache_file[cache_file_position] = '@';
83*288bf522SAndroid Build Coastguard Worker     cache_file_position = cache_file.find('/', cache_file_position);
84*288bf522SAndroid Build Coastguard Worker   }
85*288bf522SAndroid Build Coastguard Worker 
86*288bf522SAndroid Build Coastguard Worker   // Add <apk_name>.
87*288bf522SAndroid Build Coastguard Worker   std::string apk_name = ExtractAPKName(file_location);
88*288bf522SAndroid Build Coastguard Worker   if (apk_name.empty()) {
89*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to determine apk name from file name '" << file_location << "'";
90*288bf522SAndroid Build Coastguard Worker     return false;
91*288bf522SAndroid Build Coastguard Worker   }
92*288bf522SAndroid Build Coastguard Worker   std::string::size_type pos = file_location.find_last_of('.');
93*288bf522SAndroid Build Coastguard Worker   if (pos == std::string::npos) {
94*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Invalid file location '" << file_location << "'";
95*288bf522SAndroid Build Coastguard Worker     return false;
96*288bf522SAndroid Build Coastguard Worker   }
97*288bf522SAndroid Build Coastguard Worker   cache_file += apk_name;
98*288bf522SAndroid Build Coastguard Worker   std::string extension(file_location.substr(pos));
99*288bf522SAndroid Build Coastguard Worker   if (extension == ".vdex") {
100*288bf522SAndroid Build Coastguard Worker     cache_file += kVdexCacheSuffix;
101*288bf522SAndroid Build Coastguard Worker   } else if (extension == ".art") {
102*288bf522SAndroid Build Coastguard Worker     cache_file += kArtCacheSuffix;
103*288bf522SAndroid Build Coastguard Worker   } else {
104*288bf522SAndroid Build Coastguard Worker     cache_file += kOdexCacheSuffix;
105*288bf522SAndroid Build Coastguard Worker   }
106*288bf522SAndroid Build Coastguard Worker   return true;
107*288bf522SAndroid Build Coastguard Worker }
108*288bf522SAndroid Build Coastguard Worker 
109*288bf522SAndroid Build Coastguard Worker // Do the overall transformation from file_location to output_file_location. Prior to this the
110*288bf522SAndroid Build Coastguard Worker // output_file_location is empty.
SystemBFileToCacheFile(const std::string & file_location,std::string & output_file_location)111*288bf522SAndroid Build Coastguard Worker static bool SystemBFileToCacheFile(const std::string& file_location,
112*288bf522SAndroid Build Coastguard Worker                                    /*out*/std::string& output_file_location) {
113*288bf522SAndroid Build Coastguard Worker   std::string isa = ExtractISA(file_location);
114*288bf522SAndroid Build Coastguard Worker   if (isa.empty()) {
115*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to determine isa for file '" << file_location << "', skipping";
116*288bf522SAndroid Build Coastguard Worker     return false;
117*288bf522SAndroid Build Coastguard Worker   }
118*288bf522SAndroid Build Coastguard Worker   output_file_location += isa;
119*288bf522SAndroid Build Coastguard Worker   output_file_location += '/';
120*288bf522SAndroid Build Coastguard Worker   return SystemBFilenameToCacheFile(file_location, output_file_location);
121*288bf522SAndroid Build Coastguard Worker }
122*288bf522SAndroid Build Coastguard Worker 
123*288bf522SAndroid Build Coastguard Worker // This program is used to determine where in the /data directory the runtime will search for an
124*288bf522SAndroid Build Coastguard Worker // odex file if it is unable to find one at the given 'preopt-name' location. This is used to allow
125*288bf522SAndroid Build Coastguard Worker // us to store these preopted files in the unused system_b partition and copy them out on first
126*288bf522SAndroid Build Coastguard Worker // boot of the device.
main(int argc,char * argv[])127*288bf522SAndroid Build Coastguard Worker int main(int argc, char *argv[]) {
128*288bf522SAndroid Build Coastguard Worker   if (argc != 2) {
129*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "usage: preopt2cachename preopt-location";
130*288bf522SAndroid Build Coastguard Worker     return 2;
131*288bf522SAndroid Build Coastguard Worker   }
132*288bf522SAndroid Build Coastguard Worker   std::string file_location(argv[1]);
133*288bf522SAndroid Build Coastguard Worker   std::string output_file_location(kDalvikCacheDir);
134*288bf522SAndroid Build Coastguard Worker   if (!SystemBFileToCacheFile(file_location, output_file_location)) {
135*288bf522SAndroid Build Coastguard Worker     return 1;
136*288bf522SAndroid Build Coastguard Worker   } else {
137*288bf522SAndroid Build Coastguard Worker     std::cout << output_file_location;
138*288bf522SAndroid Build Coastguard Worker   }
139*288bf522SAndroid Build Coastguard Worker   return 0;
140*288bf522SAndroid Build Coastguard Worker }
141