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 "linkerconfig/librarylistloader.h"
18 
19 #include <android-base/result.h>
20 #include <android-base/strings.h>
21 #include <algorithm>
22 #include <fstream>
23 #include <iterator>
24 #include <set>
25 #include <sstream>
26 #include <unordered_map>
27 
28 #include "linkerconfig/environment.h"
29 #include "linkerconfig/log.h"
30 
31 using LibraryList = std::set<std::string>;
32 
33 using android::base::Result;
34 
35 namespace {
36 std::unordered_map<std::string, LibraryList> library_file_cache;
37 Result<LibraryList> GetLibrariesFromFile(std::string file_path) {
38   auto cached_data = library_file_cache.find(file_path);
39   if (cached_data != library_file_cache.end()) {
40     return cached_data->second;
41   }
42 
43   std::string library_name;
44   LibraryList library_list;
45   std::ifstream library_file(file_path.c_str(), std::ifstream::in);
46 
47   if (!library_file) {
48     return ErrnoErrorf("Failed to open file {}", file_path);
49   }
50 
51   while (std::getline(library_file, library_name)) {
52     library_name = android::base::Trim(library_name);
53     if (!library_name.empty()) {
54       library_list.insert(library_name);
55     }
56   }
57 
58   // TODO (b/122954981) : Remove this part when VNDK Lite is deprecated
59   // In case of VNDK-lite devices, libz should be included in LLNDK rather than
60   // VNDK-SP libraries
61   if (android::linkerconfig::modules::IsVndkLiteDevice()) {
62     if (file_path.find("llndk") != std::string::npos) {
63       library_list.insert("libz.so");
64     } else if (file_path.find("vndksp") != std::string::npos) {
65       library_list.erase("libz.so");
66     }
67   }
68 
69   library_file_cache.insert({file_path, library_list});
70 
71   return library_list;
72 }
73 }  // namespace
74 
75 namespace android {
76 namespace linkerconfig {
77 namespace generator {
78 std::string GetLibrariesString(std::string library_file_path) {
79   auto library_list_result = GetLibrariesFromFile(library_file_path);
80   if (library_list_result.ok()) {
81     return android::base::Join(*library_list_result, ':');
82   } else {
83     // Consider unavailable library file as empty
84     LOG(WARNING) << library_list_result.error();
85     return "";
86   }
87 }
88 
89 std::string GetPublicLibrariesString(std::string library_file_path,
90                                      std::string private_library_file_path) {
91   auto library_list = GetLibrariesFromFile(library_file_path);
92   auto private_library_list = GetLibrariesFromFile(private_library_file_path);
93 
94   if (!library_list.ok()) {
95     // Consider unavailable library file as empty
96     LOG(WARNING) << library_list.error();
97     return "";
98   }
99 
100   if (!private_library_list.ok()) {
101     // No private library found. All libraries are public
102     LOG(WARNING) << private_library_list.error();
103     return android::base::Join(*library_list, ':');
104   }
105 
106   LibraryList public_library_list;
107 
108   std::set_difference(
109       library_list->begin(),
110       library_list->end(),
111       private_library_list->begin(),
112       private_library_list->end(),
113       std::inserter(public_library_list, public_library_list.begin()));
114 
115   return android::base::Join(public_library_list, ':');
116 }
117 
118 std::string GetPrivateLibrariesString(std::string library_file_path,
119                                       std::string private_library_file_path) {
120   auto library_list = GetLibrariesFromFile(library_file_path);
121   auto private_library_list = GetLibrariesFromFile(private_library_file_path);
122 
123   if (!library_list.ok()) {
124     // Consider unavailable library file as empty
125     LOG(WARNING) << library_list.error();
126     return "";
127   }
128 
129   if (!private_library_list.ok()) {
130     // No private library found. All libraries are public
131     LOG(WARNING) << private_library_list.error();
132     return "";
133   }
134 
135   LibraryList private_only_library_list;
136 
137   std::set_intersection(library_list->begin(),
138                         library_list->end(),
139                         private_library_list->begin(),
140                         private_library_list->end(),
141                         std::inserter(private_only_library_list,
142                                       private_only_library_list.begin()));
143 
144   return android::base::Join(private_only_library_list, ':');
145 }
146 }  // namespace generator
147 }  // namespace linkerconfig
148 }  // namespace android
149