File: fs_mgr_vendor_overlay.cpp

package info (click to toggle)
android-platform-system-core 1%3A10.0.0%2Br36-7
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 123,760 kB
  • sloc: cpp: 197,034; ansic: 18,211; asm: 3,606; sh: 3,180; python: 2,671; java: 693; xml: 266; makefile: 237
file content (137 lines) | stat: -rw-r--r-- 5,192 bytes parent folder | download | duplicates (2)
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;
}