代码如下:
char *devname;
int ptm;
pid_t pid;
ptm = open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
if (ptm < 0) {
LOGE("[ cannot open /dev/ptmx - %s ]\n", strerror(errno));
return -1;
}
fcntl(ptm, F_SETFD, FD_CLOEXEC);
if (grantpt(ptm) || unlockpt(ptm)
|| ((devname = (char*) ptsname(ptm)) == 0)) {
LOGE("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
return -1;
}
pid = fork();
if (pid < 0) {
LOGE("- fork failed: %s -\n", strerror(errno));
return -1;
} else if (pid == 0) {
close(ptm);
int pts;
setsid();
pts = open(devname, O_RDWR);
if (pts < 0)
exit(-1);
dup2(pts, 0);
dup2(pts, 1);
dup2(pts, 2);
execl(cmd, cmd, arg0, arg1, NULL);
exit(-1);
} else {
*pProcessId = (int) pid;
return ptm;
}
调用方法:
final int[] processId = new int[1];
FileDescriptor fd = null;
fd = Exec.createSubprocess("/system/bin/sh", "-", null, processId);
基本概念:
1. tty(终端设备的统称):
tty一词源于Teletypes,或者teletypewriters。tele源于古greek,这个词根的意思是far(远)或distant(远)的意思。也就是通过串行线用打印机键盘通过阅读和发送信息的东西,后来这东西被键盘与显示器取代,所以现在叫终端比较合适。终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端设备。
2. pty(虚拟终端):
但是如果我们远程telnet到主机或使用xterm时不也需要一个终端交互么?是的,这就是虚拟终端pty(pseudo-tty)
3. pts/ptmx(pts/ptmx结合使用,进而实现pty):
pts(pseudo-terminal slave)是pty的实现方法,与ptmx(pseudo-terminal master)配合使用实现pty。
1 创建一个虚拟终端
ptm = open("/dev/ptmx", O_RDWR);
if(ptm < 0){
LOGE("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
return -1;
}
当我们用open函数打开一个"/dev/ptmx"时,会在/dev/pts目录下面产生一主(ptm)一从(pts)一对虚拟设备,并返回ptm的文件描述符(fd)。如果fd大于0表示成功否则失败。通过open函数打开的每一对虚拟设备的fd都是独立的,而且可以把fd传送给ptsname(3)去查询他的路径信息。
2 打开虚拟终端
fcntl(ptm, F_SETFD, FD_CLOEXEC);
<span style="white-space:pre"> </span>if (grantpt(ptm) || unlockpt(ptm)
|| ((devname = (char*) ptsname(ptm)) == 0)) {
LOGE("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
return -1;
}
在打开pts之前,必须先调用grantpt(3)与unlockpt(3)。grantpt(3)的作用是获得pts的访问权限。unlockpt(3)的作用是解锁这一对虚拟设备。
一但我们打开这一对虚拟设备以后,从虚拟设备就可以提供给我们一个真实终端的操作接口。写到从设备的数据将在主设备里面输出,同样写到主设备的数据将在从设备里面输出。事实上,虚拟设备被运用到实现终端的模拟器上面,好比xterm(1). 它读从ptm读数据的时候被应用中断的方式与与真实终端的方式一样。而且还可以提供如sshd(8)这般的远程登录程序,它从主设备读取数据然后通过网络传送到客户端的终端或是终端模拟器上面。
3 创建一个子进程
pid = fork();
pid < 0;创建子进程失败。
pid =0; 在子进程里面。
pid > 0; 在主进程里面。
4 制作守护进程
close(ptm);
int pts;
setsid();
pts = open(devname, O_RDWR);
if (pts < 0)
exit(-1);
dup2(pts, 0);
dup2(pts, 1);
dup2(pts, 2);
execl(cmd, cmd, arg0, arg1, NULL);
exit(-1);
setsid()是给子进程一个新的session id,这样当主进程关闭的时候,子进程不会被关闭。dup2(pts, 0/1/2)把pts这个文件描述符所代表的文件输入重定向,输出重定向,标准错误输出重定向。
execl这个函数里面的l代表list,也就是参数列表的意思。第一参数path字符指针所指向要执行的文件路径, 接下来的参数代表执行该文件时传递的参数列表:argv[0],argv[1]... 最后一个参数须用空指针NULL作结束。成功则不返回值, 失败返回-1, 失败原因存于errno中,可通过perror()打印。