lxc 简介

本文所用lxc-4.0.0版本,使用ndk26进行交叉编译,过程在此忽略。
以下启动Android系统大体流程

中间经过lxccontainer.c 构建容器

struct lxc_container *lxc_container_new(const char *name, const char *configpath)
{
	struct lxc_container *c;
	size_t len;
	int rc;
    /*
     * 开辟空间,设置挂载指针,最后给容器取个名字
     */
	c = malloc(sizeof(*c));
	memset(c, 0, sizeof(*c));

	(void)strlcpy(c->name, name, len + 1);

    //创建容器的RUN的文件夹,这里要结合交叉编译调试
	c->slock = lxc_newlock(c->config_path, name);
	if (!c->slock) {
		fprintf(stderr, "Failed to create lock for %s\n", name);
		goto err;
	}

    //检查容器的创建状态
	rc = ongoing_create(c);

	/* 设置实现函数 */
	c->is_defined = lxcapi_is_defined;
	c->want_daemonize = lxcapi_want_daemonize;
    c->start = lxcapi_start;

	return c;

err:
	lxc_container_free(c);
	return NULL;
}

进入lxc_start.c 的入口函数,最终调用容器的start函数。需注意容器启动的要么没有要么是默认参数/sbin/init

int main(int argc, char *argv[])
{
	const char *lxcpath;
	char *const *args;
	struct lxc_container *c;
	struct lxc_log log;
	int err = EXIT_FAILURE;
	char *rcfile = NULL;
	char *const default_args[] = {
		"/sbin/init",
		NULL,
	};

	lxc_list_init(&defines);
    //容器内系统功能
	if (lxc_caps_init())
		exit(err);
    //解析参数
	if (lxc_arguments_parse(&my_args, argc, argv))
		exit(err);

    //容器目录的挂载指针位置
	lxcpath = my_args.lxcpath[0];
	if (access(lxcpath, O_RDONLY) < 0) {
		ERROR("You lack access to %s", lxcpath);
		exit(err);
	}

   // 解析自定义配置文件,如果有
	if (my_args.rcfile) {
		rcfile = (char *)my_args.rcfile;
        // 创建容器
		c = lxc_container_new(my_args.name, lxcpath);
		if (!c) {
			ERROR("Failed to create lxc_container");
			exit(err);
		}
	}

	//开启容器
	if (args == default_args)
		err = c->start(c, 0, NULL) ? EXIT_SUCCESS : EXIT_FAILURE;
	else
		err = c->start(c, 0, args) ? EXIT_SUCCESS : EXIT_FAILURE;

out:
	lxc_container_put(c);
	exit(err);
}

 进入do_lxcapi_start 函数,这一步只是生了个孩子,在笔者实验下进入lxc_start 函数

static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
{
	/* initialize handler */
	handler = lxc_init_handler(c->name, conf, c->config_path, c->daemonize);

    //生孩子
	if (c->daemonize) {
		pid_first = fork();

		pid_second = fork();

		/* second parent */
		if (pid_second != 0) {
			free_init_cmd(init_cmd);
			lxc_free_handler(handler);
			_exit(EXIT_SUCCESS);
		}

		/* second child */

	}

reboot:
    //进一步在容器里执行
	if (useinit)
		ret = lxc_execute(c->name, argv, 1, handler, c->config_path,
				  c->daemonize, &c->error_num);
	else
		ret = lxc_start(argv, handler, c->config_path, c->daemonize,
				&c->error_num);
	return true;
}

进入start.c 的 __lxc_start 函数,只要用户的init进程创建出来了,那么它的父进程会被回收

int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
		void *data, const char *lxcpath, bool daemonize, int *error_num)
{
	int ret, status;
	const char *name = handler->name;
	struct lxc_conf *conf = handler->conf;
	struct cgroup_ops *cgroup_ops;
    // 设置环境变量,文件描述符,terminal终端,cgroup初始化,运行钩子函数
	ret = lxc_init(name, handler);
	if (ret < 0) {
		ERROR("Failed to initialize container \"%s\"", name);
		goto out_abort;
	}
	handler->ops = ops;
	handler->data = data;
	handler->daemonize = daemonize;
	cgroup_ops = handler->cgroup_ops;
    //克隆逼格附加块设备
	if (!attach_block_device(handler->conf)) {
		ERROR("Failed to attach block device");
		ret = -1;
		goto out_abort;
	}
    //监视器的创建和进入  
	if (!cgroup_ops->monitor_create(cgroup_ops, handler)) {
		ERROR("Failed to create monitor cgroup");
		ret = -1;
		goto out_abort;
	}

	if (!cgroup_ops->monitor_enter(cgroup_ops, handler)) {
		ERROR("Failed to enter monitor cgroup");
		ret = -1;
		goto out_abort;
	}
    
    //生成容器
	ret = lxc_spawn(handler);
	if (ret < 0) {
		ERROR("Failed to spawn container \"%s\"", name);
		goto out_detach_blockdev;
	}

	handler->conf->reboot = REBOOT_NONE;
    //利用文件描述符设置事件回调
	ret = lxc_poll(name, handler);
	if (ret) {
		ERROR("LXC mainloop exited with error: %d", ret);
		goto out_delete_network;
	}

    //回收僵尸进程
	status = lxc_wait_for_pid_status(handler->pid);
	if (status < 0)
		SYSERROR("Failed to retrieve status for %d", handler->pid);

}

最后一步,克隆进程并在里执行用户的操作系统

static int lxc_spawn(struct lxc_handler *handler)
{
	__do_close int data_sock0 = -EBADF, data_sock1 = -EBADF;
	int i, ret;
	char pidstr[20];
	bool wants_to_map_ids;
	struct lxc_list *id_map;
	const char *name = handler->name;
	const char *lxcpath = handler->lxcpath;
	bool share_ns = false;
	struct lxc_conf *conf = handler->conf;
	struct cgroup_ops *cgroup_ops = handler->cgroup_ops;

	id_map = &conf->id_map;

    // 克隆一个子进程,等待回收
	if (share_ns) {
		pid_t attacher_pid;

		attacher_pid = lxc_clone(do_share_ns, handler,
					 CLONE_VFORK | CLONE_VM | CLONE_FILES, NULL);
		if (attacher_pid < 0) {
			SYSERROR(LXC_CLONE_ERROR);
			goto out_delete_net;
		}

		ret = wait_for_pid(attacher_pid);
		if (ret < 0) {
			SYSERROR("Intermediate process failed");
			goto out_delete_net;
		}
	} else {
		handler->pid = lxc_raw_clone_cb(do_start, handler,
						CLONE_PIDFD | handler->ns_on_clone_flags,
						&handler->pidfd);
	}
	if (handler->pid < 0) {
		SYSERROR(LXC_CLONE_ERROR);
		goto out_delete_net;
	}
	TRACE("Cloned child process %d", handler->pid);

	/* 往进程发一个信号验证是否能用 */
	if (!lxc_can_use_pidfd(handler->pidfd))
		close_prot_errno_disarm(handler->pidfd);

    // 克隆标记逻辑运算
	for (i = 0; i < LXC_NS_MAX; i++)
		if (handler->ns_on_clone_flags & ns_info[i].clone_flag)
			INFO("Cloned %s", ns_info[i].flag_name);


	ret = lxc_sync_wake_child(handler, LXC_SYNC_STARTUP);
	if (ret < 0)
		goto out_delete_net;

	ret = lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE);
	if (ret < 0)
		goto out_delete_net;
    //设置,和添加cgroup层级
	if (!cgroup_ops->setup_limits_legacy(cgroup_ops, handler->conf, false)) {
		ERROR("Failed to setup cgroup limits for container \"%s\"", name);
		goto out_delete_net;
	}

    //赋予配置权限
	if (!cgroup_ops->chown(cgroup_ops, handler->conf))
		goto out_delete_net;

	ret = lxc_netns_set_nsid(handler->nsfd[LXC_NS_NET]);
	if (ret < 0)
		SYSWARN("Failed to allocate new network namespace id");
	else
		TRACE("Allocated new network namespace id");

	/*  设置网络配置 */
	if (handler->ns_clone_flags & CLONE_NEWNET) {
		ret = lxc_create_network(handler);
		if (ret < 0) {
			ERROR("Failed to create the network");
			goto out_delete_net;
		}

		ret = lxc_network_send_to_child(handler);
		if (ret < 0) {
			ERROR("Failed to send veth names to child");
			goto out_delete_net;
		}
	}
    // 设置/proc 文件系统
	if (!lxc_list_empty(&conf->procs)) {
		ret = setup_proc_filesystem(&conf->procs, handler->pid);
		if (ret < 0)
			goto out_delete_net;
	}

	/* Tell the child to continue its initialization. We'll get
	 * LXC_SYNC_CGROUP when it is ready for us to setup cgroups.
	 */
	ret = lxc_sync_barrier_child(handler, LXC_SYNC_POST_CONFIGURE);
	if (ret < 0)
		goto out_delete_net;

    // 设置cgroup2 控制器
	if (!cgroup_ops->devices_activate(cgroup_ops, handler)) {
		ERROR("Failed to setup cgroup2 device controller limits");
		goto out_delete_net;
	}
	TRACE("Set up cgroup2 device controller limits");


    // 记录网络日志
	lxc_log_configured_netdevs(conf);

	/* 读取tty设备的信息 */
	ret = lxc_recv_ttys_from_child(handler);
	if (ret < 0) {
		ERROR("Failed to receive tty info from child process");
		goto out_delete_net;
	}

    // 在容器里启动用户系统
	ret = handler->ops->post_start(handler, handler->data);
	if (ret < 0)
		goto out_abort;
    // 更改容器状态
	ret = lxc_set_state(name, handler, RUNNING);
	if (ret < 0) {
		ERROR("Failed to set state to \"%s\"", lxc_state2str(RUNNING));
		goto out_abort;
	}

	lxc_sync_fini(handler);


	return -1;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值