Merge changes from topic 'pre-early-mount' am: 1549257ff5
am: c027aac7c8
Change-Id: I58db246d8dd59d6863b43f9e4fb442e9e363de94
This commit is contained in:
commit
9e140bb206
5 changed files with 398 additions and 197 deletions
|
|
@ -25,6 +25,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <android-base/file.h>
|
||||||
|
#include <android-base/stringprintf.h>
|
||||||
|
#include <android-base/strings.h>
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
#include "fs_mgr.h"
|
#include "fs_mgr.h"
|
||||||
|
|
@ -77,8 +80,51 @@ static int get_active_slot_suffix_from_misc(struct fstab *fstab,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets slot_suffix from either the kernel cmdline / firmware or the
|
// finds slot_suffix in androidboot.slot_suffix kernel command line argument
|
||||||
// misc partition. Sets |out_suffix| on success and returns 0. Returns
|
// or in the device tree node at /firmware/android/slot_suffix property
|
||||||
|
static int get_active_slot_suffix_from_kernel(char *out_suffix,
|
||||||
|
size_t suffix_len)
|
||||||
|
{
|
||||||
|
std::string cmdline;
|
||||||
|
if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
|
||||||
|
for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
|
||||||
|
std::vector<std::string> pieces = android::base::Split(entry, "=");
|
||||||
|
if (pieces.size() == 2) {
|
||||||
|
if (pieces[0] == "androidboot.slot_suffix") {
|
||||||
|
strncpy(out_suffix, pieces[1].c_str(), suffix_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we can't find slot_suffix in cmdline, check the DT
|
||||||
|
static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
|
||||||
|
std::string file_name = android::base::StringPrintf("%s/compatible", android_dt_dir);
|
||||||
|
std::string dt_value;
|
||||||
|
if (android::base::ReadFileToString(file_name, &dt_value)) {
|
||||||
|
if (!dt_value.compare("android,firmware")) {
|
||||||
|
LERROR << "Error finding compatible android DT node";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_name = android::base::StringPrintf("%s/%s", android_dt_dir, "slot_suffix");
|
||||||
|
if (!android::base::ReadFileToString(file_name, &dt_value)) {
|
||||||
|
LERROR << "Error finding slot_suffix in device tree";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DT entries have a terminating '\0', so 'suffix_len' is safe.
|
||||||
|
strncpy(out_suffix, dt_value.c_str(), suffix_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// slot_suffix missing in kernel cmdline or device tree
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets slot_suffix from either the kernel cmdline / device tree / firmware
|
||||||
|
// or the misc partition. Sets |out_suffix| on success and returns 0. Returns
|
||||||
// -1 if slot_suffix could not be determined.
|
// -1 if slot_suffix could not be determined.
|
||||||
static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix,
|
static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix,
|
||||||
size_t suffix_len)
|
size_t suffix_len)
|
||||||
|
|
@ -94,6 +140,15 @@ static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the property is not set, we are either being invoked too early
|
||||||
|
// or the slot suffix in mentioned in the misc partition. If its
|
||||||
|
// "too early", try to find the slotsuffix ourselves in the kernel command
|
||||||
|
// line or the device tree
|
||||||
|
if (get_active_slot_suffix_from_kernel(out_suffix, suffix_len) == 0) {
|
||||||
|
LINFO << "Using slot suffix '" << out_suffix << "' from kernel";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// If we couldn't get the suffix from the kernel cmdline, try the
|
// If we couldn't get the suffix from the kernel cmdline, try the
|
||||||
// the misc partition.
|
// the misc partition.
|
||||||
if (get_active_slot_suffix_from_misc(fstab, out_suffix, suffix_len) == 0) {
|
if (get_active_slot_suffix_from_misc(fstab, out_suffix, suffix_len) == 0) {
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,7 @@ int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
|
||||||
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
|
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
|
||||||
int fs_mgr_is_notrim(struct fstab_rec *fstab);
|
int fs_mgr_is_notrim(struct fstab_rec *fstab);
|
||||||
int fs_mgr_is_formattable(struct fstab_rec *fstab);
|
int fs_mgr_is_formattable(struct fstab_rec *fstab);
|
||||||
|
int fs_mgr_is_slotselect(struct fstab_rec *fstab);
|
||||||
int fs_mgr_is_nofail(struct fstab_rec *fstab);
|
int fs_mgr_is_nofail(struct fstab_rec *fstab);
|
||||||
int fs_mgr_is_latemount(struct fstab_rec *fstab);
|
int fs_mgr_is_latemount(struct fstab_rec *fstab);
|
||||||
int fs_mgr_is_quota(struct fstab_rec *fstab);
|
int fs_mgr_is_quota(struct fstab_rec *fstab);
|
||||||
|
|
|
||||||
196
init/devices.cpp
196
init/devices.cpp
|
|
@ -62,19 +62,7 @@ static const char *firmware_dirs[] = { "/etc/firmware",
|
||||||
|
|
||||||
extern struct selabel_handle *sehandle;
|
extern struct selabel_handle *sehandle;
|
||||||
|
|
||||||
static int device_fd = -1;
|
static android::base::unique_fd device_fd;
|
||||||
|
|
||||||
struct uevent {
|
|
||||||
const char *action;
|
|
||||||
const char *path;
|
|
||||||
const char *subsystem;
|
|
||||||
const char *firmware;
|
|
||||||
const char *partition_name;
|
|
||||||
const char *device_name;
|
|
||||||
int partition_num;
|
|
||||||
int major;
|
|
||||||
int minor;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct perms_ {
|
struct perms_ {
|
||||||
char *name;
|
char *name;
|
||||||
|
|
@ -249,11 +237,13 @@ static void make_device(const char *path,
|
||||||
|
|
||||||
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
|
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
|
||||||
|
|
||||||
if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
|
if (sehandle) {
|
||||||
PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
|
if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
|
||||||
return;
|
PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setfscreatecon(secontext);
|
||||||
}
|
}
|
||||||
setfscreatecon(secontext);
|
|
||||||
|
|
||||||
dev = makedev(major, minor);
|
dev = makedev(major, minor);
|
||||||
/* Temporarily change egid to avoid race condition setting the gid of the
|
/* Temporarily change egid to avoid race condition setting the gid of the
|
||||||
|
|
@ -264,7 +254,7 @@ static void make_device(const char *path,
|
||||||
setegid(gid);
|
setegid(gid);
|
||||||
/* If the node already exists update its SELinux label to handle cases when
|
/* If the node already exists update its SELinux label to handle cases when
|
||||||
* it was created with the wrong context during coldboot procedure. */
|
* it was created with the wrong context during coldboot procedure. */
|
||||||
if (mknod(path, mode, dev) && (errno == EEXIST)) {
|
if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
|
||||||
|
|
||||||
char* fcon = nullptr;
|
char* fcon = nullptr;
|
||||||
int rc = lgetfilecon(path, &fcon);
|
int rc = lgetfilecon(path, &fcon);
|
||||||
|
|
@ -285,8 +275,10 @@ out:
|
||||||
chown(path, uid, -1);
|
chown(path, uid, -1);
|
||||||
setegid(AID_ROOT);
|
setegid(AID_ROOT);
|
||||||
|
|
||||||
freecon(secontext);
|
if (secontext) {
|
||||||
setfscreatecon(NULL);
|
freecon(secontext);
|
||||||
|
setfscreatecon(NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_platform_device(const char *path)
|
static void add_platform_device(const char *path)
|
||||||
|
|
@ -349,6 +341,19 @@ static void remove_platform_device(const char *path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void destroy_platform_devices() {
|
||||||
|
struct listnode* node;
|
||||||
|
struct listnode* n;
|
||||||
|
struct platform_node* bus;
|
||||||
|
|
||||||
|
list_for_each_safe(node, n, &platform_names) {
|
||||||
|
list_remove(node);
|
||||||
|
bus = node_to_item(node, struct platform_node, list);
|
||||||
|
free(bus->path);
|
||||||
|
free(bus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Given a path that may start with a PCI device, populate the supplied buffer
|
/* Given a path that may start with a PCI device, populate the supplied buffer
|
||||||
* with the PCI domain/bus number and the peripheral ID and return 0.
|
* with the PCI domain/bus number and the peripheral ID and return 0.
|
||||||
* If it doesn't start with a PCI device, or there is some error, return -1 */
|
* If it doesn't start with a PCI device, or there is some error, return -1 */
|
||||||
|
|
@ -515,7 +520,7 @@ static char **get_block_device_symlinks(struct uevent *uevent)
|
||||||
return NULL;
|
return NULL;
|
||||||
memset(links, 0, sizeof(char *) * 4);
|
memset(links, 0, sizeof(char *) * 4);
|
||||||
|
|
||||||
LOG(INFO) << "found " << type << " device " << device;
|
LOG(VERBOSE) << "found " << type << " device " << device;
|
||||||
|
|
||||||
snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
|
snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
|
||||||
|
|
||||||
|
|
@ -875,9 +880,15 @@ static void handle_firmware_event(uevent* uevent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool inline should_stop_coldboot(coldboot_action_t act)
|
||||||
|
{
|
||||||
|
return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
|
||||||
|
}
|
||||||
|
|
||||||
#define UEVENT_MSG_LEN 2048
|
#define UEVENT_MSG_LEN 2048
|
||||||
|
|
||||||
static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
|
static inline coldboot_action_t handle_device_fd_with(
|
||||||
|
std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
|
||||||
{
|
{
|
||||||
char msg[UEVENT_MSG_LEN+2];
|
char msg[UEVENT_MSG_LEN+2];
|
||||||
int n;
|
int n;
|
||||||
|
|
@ -890,14 +901,18 @@ static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
|
||||||
|
|
||||||
struct uevent uevent;
|
struct uevent uevent;
|
||||||
parse_event(msg, &uevent);
|
parse_event(msg, &uevent);
|
||||||
handle_uevent(&uevent);
|
coldboot_action_t act = handle_uevent(&uevent);
|
||||||
|
if (should_stop_coldboot(act))
|
||||||
|
return act;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return COLDBOOT_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_device_fd()
|
coldboot_action_t handle_device_fd(coldboot_callback fn)
|
||||||
{
|
{
|
||||||
handle_device_fd_with(
|
coldboot_action_t ret = handle_device_fd_with(
|
||||||
[](struct uevent *uevent) {
|
[&](uevent* uevent) -> coldboot_action_t {
|
||||||
if (selinux_status_updated() > 0) {
|
if (selinux_status_updated() > 0) {
|
||||||
struct selabel_handle *sehandle2;
|
struct selabel_handle *sehandle2;
|
||||||
sehandle2 = selinux_android_file_context_handle();
|
sehandle2 = selinux_android_file_context_handle();
|
||||||
|
|
@ -907,9 +922,21 @@ void handle_device_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_device_event(uevent);
|
// default is to always create the devices
|
||||||
handle_firmware_event(uevent);
|
coldboot_action_t act = COLDBOOT_CREATE;
|
||||||
|
if (fn) {
|
||||||
|
act = fn(uevent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
|
||||||
|
handle_device_event(uevent);
|
||||||
|
handle_firmware_event(uevent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return act;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Coldboot walks parts of the /sys tree and pokes the uevent files
|
/* Coldboot walks parts of the /sys tree and pokes the uevent files
|
||||||
|
|
@ -921,21 +948,24 @@ void handle_device_fd()
|
||||||
** socket's buffer.
|
** socket's buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void do_coldboot(DIR *d)
|
static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
|
||||||
{
|
{
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
int dfd, fd;
|
int dfd, fd;
|
||||||
|
coldboot_action_t act = COLDBOOT_CONTINUE;
|
||||||
|
|
||||||
dfd = dirfd(d);
|
dfd = dirfd(d);
|
||||||
|
|
||||||
fd = openat(dfd, "uevent", O_WRONLY);
|
fd = openat(dfd, "uevent", O_WRONLY);
|
||||||
if(fd >= 0) {
|
if (fd >= 0) {
|
||||||
write(fd, "add\n", 4);
|
write(fd, "add\n", 4);
|
||||||
close(fd);
|
close(fd);
|
||||||
handle_device_fd();
|
act = handle_device_fd(fn);
|
||||||
|
if (should_stop_coldboot(act))
|
||||||
|
return act;
|
||||||
}
|
}
|
||||||
|
|
||||||
while((de = readdir(d))) {
|
while (!should_stop_coldboot(act) && (de = readdir(d))) {
|
||||||
DIR *d2;
|
DIR *d2;
|
||||||
|
|
||||||
if(de->d_type != DT_DIR || de->d_name[0] == '.')
|
if(de->d_type != DT_DIR || de->d_name[0] == '.')
|
||||||
|
|
@ -949,85 +979,31 @@ static void do_coldboot(DIR *d)
|
||||||
if(d2 == 0)
|
if(d2 == 0)
|
||||||
close(fd);
|
close(fd);
|
||||||
else {
|
else {
|
||||||
do_coldboot(d2);
|
act = do_coldboot(d2, fn);
|
||||||
closedir(d2);
|
closedir(d2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// default is always to continue looking for uevents
|
||||||
|
return act;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coldboot(const char *path)
|
static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
|
||||||
{
|
{
|
||||||
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
|
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
|
||||||
if(d) {
|
if (d) {
|
||||||
do_coldboot(d.get());
|
return do_coldboot(d.get(), fn);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
char devpath[DEVPATH_LEN];
|
|
||||||
|
|
||||||
if (is_block && strncmp(uevent->subsystem, "block", 5))
|
|
||||||
return;
|
|
||||||
|
|
||||||
name = parse_device_name(uevent, MAX_DEV_NAME);
|
|
||||||
if (!name) {
|
|
||||||
LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
|
|
||||||
<< " " << uevent->partition_name << " " << uevent->partition_num
|
|
||||||
<< " " << uevent->major << ":" << uevent->minor;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(devpath, sizeof(devpath), "%s%s", base, name);
|
return COLDBOOT_CONTINUE;
|
||||||
make_dir(base, 0755);
|
|
||||||
|
|
||||||
dev_t dev = makedev(uevent->major, uevent->minor);
|
|
||||||
mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
|
|
||||||
mknod(devpath, mode, dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void early_create_dev(const std::string& syspath, early_device_type dev_type)
|
void device_init(const char* path, coldboot_callback fn) {
|
||||||
{
|
|
||||||
android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
|
|
||||||
if (dfd < 0) {
|
|
||||||
LOG(ERROR) << "Failed to open " << syspath;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
|
|
||||||
if (fd < 0) {
|
|
||||||
LOG(ERROR) << "Failed to open " << syspath << "/uevent";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fcntl(device_fd, F_SETFL, O_NONBLOCK);
|
|
||||||
|
|
||||||
write(fd, "add\n", 4);
|
|
||||||
handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
|
|
||||||
[](struct uevent *uevent) {
|
|
||||||
early_uevent_handler(uevent, "/dev/block/", true);
|
|
||||||
} :
|
|
||||||
[](struct uevent *uevent) {
|
|
||||||
early_uevent_handler(uevent, "/dev/", false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int early_device_socket_open() {
|
|
||||||
device_fd = uevent_open_socket(256*1024, true);
|
|
||||||
return device_fd < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void early_device_socket_close() {
|
|
||||||
close(device_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void device_init() {
|
|
||||||
sehandle = selinux_android_file_context_handle();
|
sehandle = selinux_android_file_context_handle();
|
||||||
selinux_status_open(true);
|
selinux_status_open(true);
|
||||||
|
|
||||||
/* is 256K enough? udev uses 16MB! */
|
/* is 256K enough? udev uses 16MB! */
|
||||||
device_fd = uevent_open_socket(256*1024, true);
|
device_fd.reset(uevent_open_socket(256*1024, true));
|
||||||
if (device_fd == -1) {
|
if (device_fd == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1039,13 +1015,33 @@ void device_init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer t;
|
Timer t;
|
||||||
coldboot("/sys/class");
|
coldboot_action_t act;
|
||||||
coldboot("/sys/block");
|
if (!path) {
|
||||||
coldboot("/sys/devices");
|
act = coldboot("/sys/class", fn);
|
||||||
close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
|
if (!should_stop_coldboot(act)) {
|
||||||
|
act = coldboot("/sys/block", fn);
|
||||||
|
if (!should_stop_coldboot(act)) {
|
||||||
|
act = coldboot("/sys/devices", fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
act = coldboot(path, fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a callback, then do as it says. If no, then the default is
|
||||||
|
// to always create COLDBOOT_DONE file.
|
||||||
|
if (!fn || (act == COLDBOOT_FINISH)) {
|
||||||
|
close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
|
||||||
|
}
|
||||||
|
|
||||||
LOG(INFO) << "Coldboot took " << t;
|
LOG(INFO) << "Coldboot took " << t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void device_close() {
|
||||||
|
destroy_platform_devices();
|
||||||
|
device_fd.reset();
|
||||||
|
}
|
||||||
|
|
||||||
int get_device_fd() {
|
int get_device_fd() {
|
||||||
return device_fd;
|
return device_fd;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,16 +17,37 @@
|
||||||
#ifndef _INIT_DEVICES_H
|
#ifndef _INIT_DEVICES_H
|
||||||
#define _INIT_DEVICES_H
|
#define _INIT_DEVICES_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
extern void handle_device_fd();
|
enum coldboot_action_t {
|
||||||
extern void device_init(void);
|
// coldboot continues without creating the device for the uevent
|
||||||
|
COLDBOOT_CONTINUE = 0,
|
||||||
|
// coldboot continues after creating the device for the uevent
|
||||||
|
COLDBOOT_CREATE,
|
||||||
|
// coldboot stops after creating the device for uevent but doesn't
|
||||||
|
// create the COLDBOOT_DONE file
|
||||||
|
COLDBOOT_STOP,
|
||||||
|
// same as COLDBOOT_STOP, but creates the COLDBOOT_DONE file
|
||||||
|
COLDBOOT_FINISH
|
||||||
|
};
|
||||||
|
|
||||||
enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
|
struct uevent {
|
||||||
|
const char* action;
|
||||||
|
const char* path;
|
||||||
|
const char* subsystem;
|
||||||
|
const char* firmware;
|
||||||
|
const char* partition_name;
|
||||||
|
const char* device_name;
|
||||||
|
int partition_num;
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
};
|
||||||
|
|
||||||
extern int early_device_socket_open();
|
typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback;
|
||||||
extern void early_device_socket_close();
|
extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr);
|
||||||
extern void early_create_dev(const std::string& syspath, early_device_type dev_type);
|
extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr);
|
||||||
|
extern void device_close();
|
||||||
|
|
||||||
extern int add_dev_perms(const char *name, const char *attr,
|
extern int add_dev_perms(const char *name, const char *attr,
|
||||||
mode_t perm, unsigned int uid,
|
mode_t perm, unsigned int uid,
|
||||||
|
|
|
||||||
306
init/init.cpp
306
init/init.cpp
|
|
@ -495,28 +495,48 @@ static void export_kernel_boot_props() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_kernel_dt() {
|
static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
|
||||||
static const char android_dir[] = "/proc/device-tree/firmware/android";
|
|
||||||
|
|
||||||
std::string file_name = StringPrintf("%s/compatible", android_dir);
|
static bool is_dt_compatible() {
|
||||||
|
std::string dt_value;
|
||||||
|
std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
|
||||||
|
|
||||||
std::string dt_file;
|
android::base::ReadFileToString(file_name, &dt_value);
|
||||||
android::base::ReadFileToString(file_name, &dt_file);
|
if (!dt_value.compare("android,firmware")) {
|
||||||
if (!dt_file.compare("android,firmware")) {
|
|
||||||
LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
|
LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_dt_fstab_compatible() {
|
||||||
|
std::string dt_value;
|
||||||
|
std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
|
||||||
|
|
||||||
|
android::base::ReadFileToString(file_name, &dt_value);
|
||||||
|
if (!dt_value.compare("android,fstab")) {
|
||||||
|
LOG(ERROR) << "firmware/android/fstab is not compatible with 'android,fstab'";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_kernel_dt() {
|
||||||
|
if (!is_dt_compatible()) return;
|
||||||
|
|
||||||
|
std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
|
||||||
if (!dir) return;
|
if (!dir) return;
|
||||||
|
|
||||||
|
std::string dt_file;
|
||||||
struct dirent *dp;
|
struct dirent *dp;
|
||||||
while ((dp = readdir(dir.get())) != NULL) {
|
while ((dp = readdir(dir.get())) != NULL) {
|
||||||
if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {
|
if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
|
std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);
|
||||||
|
|
||||||
android::base::ReadFileToString(file_name, &dt_file);
|
android::base::ReadFileToString(file_name, &dt_file);
|
||||||
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
|
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
|
||||||
|
|
@ -643,102 +663,208 @@ static void set_usb_controller() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a new path consisting of base_path and the file name in reference_path. */
|
static std::string import_dt_fstab() {
|
||||||
static std::string get_path(const std::string& base_path, const std::string& reference_path) {
|
std::string fstab;
|
||||||
std::string::size_type pos = reference_path.rfind('/');
|
if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
|
||||||
if (pos == std::string::npos) {
|
return fstab;
|
||||||
return base_path + '/' + reference_path;
|
|
||||||
} else {
|
|
||||||
return base_path + reference_path.substr(pos);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Imports the fstab info from cmdline. */
|
std::string fstabdir_name = StringPrintf("%s/fstab", android_dt_dir);
|
||||||
static std::string import_cmdline_fstab() {
|
std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
|
||||||
std::string prefix, fstab, fstab_full;
|
if (!fstabdir) return fstab;
|
||||||
|
|
||||||
import_kernel_cmdline(false,
|
dirent* dp;
|
||||||
[&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
|
while ((dp = readdir(fstabdir.get())) != NULL) {
|
||||||
if (key == "android.early.prefix") {
|
// skip over name and compatible
|
||||||
prefix = value;
|
if (dp->d_type != DT_DIR) {
|
||||||
} else if (key == "android.early.fstab") {
|
continue;
|
||||||
fstab = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!fstab.empty()) {
|
|
||||||
// Convert "mmcblk0p09+/odm+ext4+ro+verify" to "mmcblk0p09 /odm ext4 ro verify"
|
|
||||||
std::replace(fstab.begin(), fstab.end(), '+', ' ');
|
|
||||||
for (const auto& entry : android::base::Split(fstab, "\n")) {
|
|
||||||
fstab_full += prefix + entry + '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip if its not 'vendor', 'odm' or 'system'
|
||||||
|
if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
|
||||||
|
strcmp(dp->d_name, "vendor")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
|
||||||
|
std::vector<std::string> fstab_entry;
|
||||||
|
std::string file_name;
|
||||||
|
std::string value;
|
||||||
|
file_name = StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
|
||||||
|
if (!android::base::ReadFileToString(file_name, &value)) {
|
||||||
|
LOG(ERROR) << "dt_fstab: Failed to find device for partition " << dp->d_name;
|
||||||
|
fstab.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// trim the terminating '\0' out
|
||||||
|
value.resize(value.size() - 1);
|
||||||
|
fstab_entry.push_back(value);
|
||||||
|
fstab_entry.push_back(StringPrintf("/%s", dp->d_name));
|
||||||
|
|
||||||
|
file_name = StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
|
||||||
|
if (!android::base::ReadFileToString(file_name, &value)) {
|
||||||
|
LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
|
||||||
|
fstab.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value.resize(value.size() - 1);
|
||||||
|
fstab_entry.push_back(value);
|
||||||
|
|
||||||
|
file_name = StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
|
||||||
|
if (!android::base::ReadFileToString(file_name, &value)) {
|
||||||
|
LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
|
||||||
|
fstab.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value.resize(value.size() - 1);
|
||||||
|
fstab_entry.push_back(value);
|
||||||
|
|
||||||
|
file_name = StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
|
||||||
|
if (!android::base::ReadFileToString(file_name, &value)) {
|
||||||
|
LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
|
||||||
|
fstab.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value.resize(value.size() - 1);
|
||||||
|
fstab_entry.push_back(value);
|
||||||
|
|
||||||
|
fstab += android::base::Join(fstab_entry, " ");
|
||||||
|
fstab += '\n';
|
||||||
}
|
}
|
||||||
return fstab_full;
|
|
||||||
|
return fstab;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
|
/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
|
||||||
static void early_mount() {
|
static bool early_mount() {
|
||||||
std::string fstab_string = import_cmdline_fstab();
|
std::string fstab = import_dt_fstab();
|
||||||
if (fstab_string.empty()) {
|
if (fstab.empty()) {
|
||||||
LOG(INFO) << "Failed to load vendor fstab from kernel cmdline";
|
LOG(INFO) << "Early mount skipped (missing fstab in device tree)";
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
FILE *fstab_file = fmemopen((void *)fstab_string.c_str(), fstab_string.length(), "r");
|
|
||||||
|
std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
|
||||||
|
fmemopen(static_cast<void*>(const_cast<char*>(fstab.c_str())), fstab.length(), "r"), fclose);
|
||||||
if (!fstab_file) {
|
if (!fstab_file) {
|
||||||
PLOG(ERROR) << "Failed to open fstab string as FILE";
|
PLOG(ERROR) << "Early mount failed to open fstab file in memory";
|
||||||
return;
|
return false;
|
||||||
}
|
|
||||||
std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_file(fstab_file), fs_mgr_free_fstab);
|
|
||||||
fclose(fstab_file);
|
|
||||||
if (!fstab) {
|
|
||||||
LOG(ERROR) << "Failed to parse fstab string: " << fstab_string;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOG(INFO) << "Loaded vendor fstab from cmdline";
|
|
||||||
|
|
||||||
if (early_device_socket_open()) {
|
|
||||||
LOG(ERROR) << "Failed to open device uevent socket";
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create /dev/device-mapper for dm-verity */
|
std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> tab(
|
||||||
early_create_dev("/sys/devices/virtual/misc/device-mapper", EARLY_CHAR_DEV);
|
fs_mgr_read_fstab_file(fstab_file.get()), fs_mgr_free_fstab);
|
||||||
|
if (!tab) {
|
||||||
|
LOG(ERROR) << "Early mount fsmgr failed to load fstab from kernel:" << std::endl << fstab;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < fstab->num_entries; ++i) {
|
// find out fstab records for odm, system and vendor
|
||||||
struct fstab_rec *rec = &fstab->recs[i];
|
fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
|
||||||
std::string mount_point = rec->mount_point;
|
fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
|
||||||
std::string syspath = rec->blk_device;
|
fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
|
||||||
|
if (!odm_rec && !system_rec && !vendor_rec) {
|
||||||
|
// nothing to early mount
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mount_point != "/vendor" && mount_point != "/odm")
|
// assume A/B device if we find 'slotselect' in any fstab entry
|
||||||
continue;
|
bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
|
||||||
|
(system_rec && fs_mgr_is_slotselect(system_rec)) ||
|
||||||
|
(vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
|
||||||
|
bool found_odm = !odm_rec;
|
||||||
|
bool found_system = !system_rec;
|
||||||
|
bool found_vendor = !vendor_rec;
|
||||||
|
int count_odm = 0, count_vendor = 0, count_system = 0;
|
||||||
|
|
||||||
/* Create mount target under /dev/block/ from sysfs via uevent */
|
// create the devices we need..
|
||||||
LOG(INFO) << "Mounting " << mount_point << " from " << syspath << "...";
|
device_init(nullptr, [&](uevent* uevent) -> coldboot_action_t {
|
||||||
char *devpath = strdup(get_path("/dev/block", syspath).c_str());
|
if (!strncmp(uevent->subsystem, "firmware", 8)) {
|
||||||
if (!devpath) {
|
return COLDBOOT_CONTINUE;
|
||||||
PLOG(ERROR) << "Failed to strdup dev path in early mount " << syspath;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
rec->blk_device = devpath;
|
|
||||||
early_create_dev(syspath, EARLY_BLOCK_DEV);
|
|
||||||
|
|
||||||
int rc = fs_mgr_early_setup_verity(rec);
|
|
||||||
if (rc == FS_MGR_EARLY_SETUP_VERITY_SUCCESS) {
|
|
||||||
/* Mount target is changed to /dev/block/dm-<n>; initiate its creation from sysfs counterpart */
|
|
||||||
early_create_dev(get_path("/sys/devices/virtual/block", rec->blk_device), EARLY_BLOCK_DEV);
|
|
||||||
} else if (rc == FS_MGR_EARLY_SETUP_VERITY_FAIL) {
|
|
||||||
LOG(ERROR) << "Failed to set up dm-verity on " << rec->blk_device;
|
|
||||||
continue;
|
|
||||||
} else { /* FS_MGR_EARLY_SETUP_VERITY_NO_VERITY */
|
|
||||||
LOG(INFO) << "dm-verity disabled on debuggable device; mount directly on " << rec->blk_device;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdir(mount_point.c_str(), 0755);
|
// we need platform devices to create symlinks
|
||||||
rc = mount(rec->blk_device, mount_point.c_str(), rec->fs_type, rec->flags, rec->fs_options);
|
if (!strncmp(uevent->subsystem, "platform", 8)) {
|
||||||
if (rc) {
|
return COLDBOOT_CREATE;
|
||||||
PLOG(ERROR) << "Failed to mount on " << rec->blk_device;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore everything that is not a block device
|
||||||
|
if (strncmp(uevent->subsystem, "block", 5)) {
|
||||||
|
return COLDBOOT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
coldboot_action_t ret;
|
||||||
|
bool create_this_node = false;
|
||||||
|
if (uevent->partition_name) {
|
||||||
|
// prefix match partition names so we create device nodes for
|
||||||
|
// A/B-ed partitions
|
||||||
|
if (!found_odm && !strncmp(uevent->partition_name, "odm", 3)) {
|
||||||
|
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
|
||||||
|
|
||||||
|
// wait twice for A/B-ed partitions
|
||||||
|
count_odm++;
|
||||||
|
if (!is_ab) {
|
||||||
|
found_odm = true;
|
||||||
|
} else if (count_odm == 2) {
|
||||||
|
found_odm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_this_node = true;
|
||||||
|
} else if (!found_system && !strncmp(uevent->partition_name, "system", 6)) {
|
||||||
|
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
|
||||||
|
|
||||||
|
count_system++;
|
||||||
|
if (!is_ab) {
|
||||||
|
found_system = true;
|
||||||
|
} else if (count_system == 2) {
|
||||||
|
found_system = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_this_node = true;
|
||||||
|
} else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
|
||||||
|
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
|
||||||
|
count_vendor++;
|
||||||
|
if (!is_ab) {
|
||||||
|
found_vendor = true;
|
||||||
|
} else if (count_vendor == 2) {
|
||||||
|
found_vendor = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_this_node = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we found all other partitions already, create this
|
||||||
|
// node and stop coldboot. If this is a prefix matched
|
||||||
|
// partition, create device node and continue. For everything
|
||||||
|
// else skip the device node
|
||||||
|
if (found_odm && found_system && found_vendor) {
|
||||||
|
ret = COLDBOOT_STOP;
|
||||||
|
} else if (create_this_node) {
|
||||||
|
ret = COLDBOOT_CREATE;
|
||||||
|
} else {
|
||||||
|
ret = COLDBOOT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: add support to mount partitions w/ verity
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
if (odm_rec &&
|
||||||
|
(ret = fs_mgr_do_mount(tab.get(), odm_rec->mount_point, odm_rec->blk_device, NULL))) {
|
||||||
|
PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting odm";
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
early_device_socket_close();
|
|
||||||
|
if (vendor_rec &&
|
||||||
|
(ret = fs_mgr_do_mount(tab.get(), vendor_rec->mount_point, vendor_rec->blk_device, NULL))) {
|
||||||
|
PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting vendor";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_close();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
|
@ -787,8 +913,10 @@ int main(int argc, char** argv) {
|
||||||
LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
|
LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
|
||||||
|
|
||||||
if (is_first_stage) {
|
if (is_first_stage) {
|
||||||
// Mount devices defined in android.early.* kernel commandline
|
if (!early_mount()) {
|
||||||
early_mount();
|
LOG(ERROR) << "Failed to mount required partitions early ...";
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
// Set up SELinux, loading the SELinux policy.
|
// Set up SELinux, loading the SELinux policy.
|
||||||
selinux_initialize(true);
|
selinux_initialize(true);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue