1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <dirent.h>
#include <selinux/selinux.h>
#include <sys/mount.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <fs_mgr_overlayfs.h>
#include <fs_mgr_vendor_overlay.h>
#include <fstab/fstab.h>
#include "fs_mgr_priv.h"
using namespace std::literals;
namespace {
// The order of the list means the priority to show the files in the directory.
// The last one has the highest priority.
const std::vector<const std::string> kVendorOverlaySourceDirs = {
"/system/vendor_overlay/",
"/product/vendor_overlay/",
};
const auto kVndkVersionPropertyName = "ro.vndk.version"s;
const auto kVendorTopDir = "/vendor/"s;
const auto kLowerdirOption = "lowerdir="s;
std::vector<std::pair<std::string, std::string>> fs_mgr_get_vendor_overlay_dirs(
const std::string& vndk_version) {
std::vector<std::pair<std::string, std::string>> vendor_overlay_dirs;
for (const auto& vendor_overlay_source : kVendorOverlaySourceDirs) {
const auto overlay_top = vendor_overlay_source + vndk_version;
std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
closedir);
if (!vendor_overlay_top) continue;
// Vendor overlay root for current vendor version found!
LINFO << "vendor overlay root: " << overlay_top;
struct dirent* dp;
while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
continue;
}
vendor_overlay_dirs.emplace_back(overlay_top, dp->d_name);
}
}
return vendor_overlay_dirs;
}
bool fs_mgr_vendor_overlay_mount(const std::pair<std::string, std::string>& mount_point) {
const auto [overlay_top, mount_dir] = mount_point;
const auto vendor_mount_point = kVendorTopDir + mount_dir;
LINFO << "vendor overlay mount on " << vendor_mount_point;
const auto target_context = fs_mgr_get_context(vendor_mount_point);
if (target_context.empty()) {
PERROR << " failed: cannot find the target vendor mount point";
return false;
}
const auto source_directory = overlay_top + "/" + mount_dir;
const auto source_context = fs_mgr_get_context(source_directory);
if (target_context != source_context) {
LERROR << " failed: source and target contexts do not match (source:" << source_context
<< ", target:" << target_context << ")";
return false;
}
auto options = kLowerdirOption + source_directory + ":" + vendor_mount_point;
if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
options += ",override_creds=off";
}
auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," +
options + ")=";
auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
options.c_str());
if (ret) {
PERROR << report << ret;
return false;
} else {
LINFO << report << ret;
return true;
}
}
} // namespace
// Since the vendor overlay requires to know the version of the vendor partition,
// it is not possible to mount vendor overlay at the first stage that cannot
// initialize properties.
// To read the properties, vendor overlay must be mounted at the second stage, right
// after "property_load_boot_defaults()" is called.
bool fs_mgr_vendor_overlay_mount_all() {
// To read the property, it must be called at the second init stage after the default
// properties are loaded.
static const auto vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
if (vndk_version.empty()) {
LINFO << "vendor overlay: vndk version not defined";
return false;
}
const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(vndk_version);
if (vendor_overlay_dirs.empty()) return true;
if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
LINFO << "vendor overlay: kernel does not support overlayfs";
return false;
}
// Mount each directory in /(system|product)/vendor_overlay/<ver> on /vendor
auto ret = true;
for (const auto& vendor_overlay_dir : vendor_overlay_dirs) {
if (!fs_mgr_vendor_overlay_mount(vendor_overlay_dir)) {
ret = false;
}
}
return ret;
}
|