1 /*
2  * Copyright (C) 2023 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  * This file contains the vendor-apex-specific functions of apexd
17  */
18 
19 #include "apexd_vendor_apex.h"
20 
21 #include <android-base/strings.h>
22 #include <vintf/VintfObject.h>
23 
24 #include "apex_file_repository.h"
25 #include "apexd_private.h"
26 #include "statslog_apex.h"
27 
28 using android::base::Error;
29 using android::base::StartsWith;
30 
31 namespace android {
32 namespace apex {
33 
34 // Returns if apex is a vendor apex, works by testing path of its preinstalled
35 // version NOTE: If BOARD_USES_VENDORIMAGE is false, then /vendor will be a
36 // symlink to
37 //    /system/vendor. Apexd handles "realpath"s for apexes. Hence when checking
38 //    if an Apex is a vendor apex with path, we need to check against both.
IsVendorApex(const ApexFile & apex_file)39 bool IsVendorApex(const ApexFile& apex_file) {
40   const auto& instance = ApexFileRepository::GetInstance();
41   const auto& preinstalled =
42       instance.GetPreInstalledApex(apex_file.GetManifest().name());
43   const auto& preinstalled_path = preinstalled.get().GetPath();
44   return (StartsWith(preinstalled_path, "/vendor/apex/") ||
45           StartsWith(preinstalled_path, "/system/vendor/apex/"));
46 }
47 
48 // Checks Compatibility for incoming vendor apex.
49 //    Adds the data from apex's vintf_fragment(s) and tests compatibility.
CheckVendorApexUpdate(const ApexFile & apex_file,const std::string & apex_mount_point)50 base::Result<void> CheckVendorApexUpdate(const ApexFile& apex_file,
51                                          const std::string& apex_mount_point) {
52   std::string error;
53 
54   const std::string apex_name = apex_file.GetManifest().name();
55 
56   std::string path_to_replace =
57       apexd_private::GetActiveMountPoint(apex_file.GetManifest());
58 
59   // Create PathReplacingFileSystem instance containing caller's path
60   // substitution
61   std::unique_ptr<vintf::FileSystem> path_replaced_fs =
62       std::make_unique<vintf::details::PathReplacingFileSystem>(
63           std::move(path_to_replace), apex_mount_point,
64           std::make_unique<vintf::details::FileSystemImpl>());
65 
66   // Create a new VintfObject that uses our path-replacing FileSystem instance
67   auto vintf_with_replaced_path =
68       vintf::VintfObject::Builder()
69           .setFileSystem(std::move(path_replaced_fs))
70           .build();
71 
72   // Disable RuntimeInfo components. Allows callers to run check
73   // without requiring read permission of restricted resources
74   auto flags = vintf::CheckFlags::DEFAULT;
75   flags = flags.disableRuntimeInfo();
76 
77   // checkCompatibility on vintfObj using the replacement vintf directory
78   int ret = vintf_with_replaced_path->checkCompatibility(&error, flags);
79   LOG(DEBUG) << "CheckVendorApexUpdate: check on vendor apex " << apex_name
80              << " returned " << ret << " (want " << vintf::COMPATIBLE
81              << " == COMPATIBLE)";
82   if (ret == vintf::INCOMPATIBLE) {
83     return Error() << "vendor apex is not compatible, error=" << error;
84   } else if (ret != vintf::COMPATIBLE) {
85     return Error() << "Check of vendor apex failed, error=" << error;
86   }
87 
88   return {};
89 }
90 
91 // GetPreinstallPartitionEnum returns the enumeration value of the preinstall-
92 //    partition of the passed apex_file
GetPreinstallPartitionEnum(const ApexFile & apex_file)93 int GetPreinstallPartitionEnum(const ApexFile& apex_file) {
94   const auto& instance = ApexFileRepository::GetInstance();
95   // We must test if this apex has a pre-installed version before calling
96   // GetPreInstalledApex() - throws an exception if apex doesn't have one
97   if (!instance.IsPreInstalledApex(apex_file)) {
98     return stats::apex::
99         APEX_INSTALLATION_REQUESTED__APEX_PREINSTALL_PARTITION__PARTITION_OTHER;
100   }
101   const auto& preinstalled =
102       instance.GetPreInstalledApex(apex_file.GetManifest().name());
103   const auto& preinstalled_path = preinstalled.get().GetPath();
104   if (StartsWith(preinstalled_path, "/vendor/") ||
105       StartsWith(preinstalled_path, "/system/vendor/")) {
106     return stats::apex::
107         APEX_INSTALLATION_REQUESTED__APEX_PREINSTALL_PARTITION__PARTITION_VENDOR;
108   }
109   if (StartsWith(preinstalled_path, "/system_ext/")) {
110     return stats::apex::
111         APEX_INSTALLATION_REQUESTED__APEX_PREINSTALL_PARTITION__PARTITION_SYSTEM_EXT;
112   }
113   if (StartsWith(preinstalled_path, "/system/")) {
114     return stats::apex::
115         APEX_INSTALLATION_REQUESTED__APEX_PREINSTALL_PARTITION__PARTITION_SYSTEM;
116   }
117   if (StartsWith(preinstalled_path, "/product/")) {
118     return stats::apex::
119         APEX_INSTALLATION_REQUESTED__APEX_PREINSTALL_PARTITION__PARTITION_PRODUCT;
120   }
121   return stats::apex::
122       APEX_INSTALLATION_REQUESTED__APEX_PREINSTALL_PARTITION__PARTITION_OTHER;
123 }
124 
125 }  // namespace apex
126 }  // namespace android
127