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