android apk安裝最後使用服務installd來實現,源碼路徑:frameworks/base/cmds/installd
$ ls -l frameworks/base/cmds/installd
total 68
-rw-r--r-- 1 lizhiguo lizhiguo 2321 2011-11-15 17:06 Android.mk
-rw-r--r-- 1 lizhiguo lizhiguo 34863 2011-11-15 17:06 commands.c
-rw-r--r-- 1 lizhiguo lizhiguo 9742 2011-11-15 17:06 installd.c
-rw-r--r-- 1 lizhiguo lizhiguo 5586 2011-11-15 17:06 installd.h
-rw-r--r-- 1 lizhiguo lizhiguo 6902 2011-11-15 17:06 utils.c
frameworks/base/services/java/com/android/server/Installer.java該文件中實現了java的Installer類,負責和Installd通信,主要實現的功能包括:
connect,disconnect,execute,install,dexopt,movedex等,對應於installd裏面的功能:
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
{ "install", 4, do_install },
{ "dexopt", 3, do_dexopt },
{ "movedex", 2, do_move_dex },
{ "rmdex", 1, do_rm_dex },
{ "remove", 2, do_remove },
{ "rename", 3, do_rename },
{ "freecache", 1, do_free_cache },
{ "rmcache", 2, do_rm_cache },
{ "protect", 2, do_protect },
{ "getsize", 4, do_get_size },
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
{ "linklib", 2, do_linklib },
{ "unlinklib", 1, do_unlinklib },
};
@ frameworks/base/cmds/installd/installd.c
int main(const int argc, const char *argv[]) {
char buf[BUFFER_MAX];
struct sockaddr addr;
socklen_t alen;
int lsocket, s, count;
lsocket = android_get_control_socket(SOCKET_PATH); // #define SOCKET_PATH "installd"
// frameworks/base/cmds/installd/installd.h
// 獲得socket的描述符,見後註釋
...
if (listen(lsocket, 5)) {
LOGE("Listen on socket failed: %s\n", strerror(errno));
exit(1);
}
fcntl(lsocket, F_SETFD, FD_CLOEXEC);
LOGI("new connection\n");
for (;;) {
unsigned short count;
if (readx(s, &count, sizeof(count))) {
LOGE("failed to read size\n");
break;
} // 讀數據大小
if ((count < 1) || (count >= BUFFER_MAX)) {
LOGE("invalid size %d\n", count);
break;
}
if (readx(s, buf, count)) {
LOGE("failed to read command\n");
break;
} // 讀實際數據
buf[count] = 0;
if (execute(s, buf)) break; // 執行命令
}
LOGI("closing connection\n");
close(s);
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
@ system/core/include/cutils/Sockets.h
#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
#define ANDROID_SOCKET_DIR "/dev/socket"
static inline int android_get_control_socket(const char *name)
{
char key[64] = ANDROID_SOCKET_ENV_PREFIX; // ANDROID_SOCKET_
const char *val;
int fd;
...
strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
key[sizeof(key)-1] = '\0';
...
val = getenv(key); // 從環境變量中得到這個key值,那麼它什麼時候設置的呢?
if (!val)
return -1;
errno = 0;
fd = strtol(val, NULL, 10);
if (errno)
return -1;
return fd;
}
/*
* See also android.os.LocalSocketAddress.Namespace
*/
// Linux "abstract" (non-filesystem) namespace
#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
// Android "reserved" (/dev/socket) namespace
#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
// Normal filesystem namespace
#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
系統屬性區是在init進程啓動過程中初始化的,而起在init.rc中會發現如下的語句:
service installd /system/bin/installd
socket installd stream 600 system system
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
在描述啓動服務的語句時,會跟上關於這個服務的所有options,而這裏socket就是其中一項option。
1. 系統屬性區和屬性服務的建立
android的每一個版本的init代碼都有一些差別,所以以下是android2.3的init代碼:
@ system/core/init/init.c
int main(int argc, char **argv)
{
...
queue_builtin_action(property_init_action, "property_init");
// 在這裏來來初始化屬性區域。
...
queue_builtin_action(property_service_init_action, "property_service_init");
// 開啓屬性服務,會導入其餘三個文件:/system/build.prop,/system/default.prop, /data/local.prop中的屬性和/data/property中的persist.開頭的屬性。
// 然後加上lcd density的屬性,ro.sf.lcd_density默認是160(MDPI), 從底層讀取像素值判斷是否是120(LDPI),240(HDPI).
// @ system/core/init/proerty_service.c
// @ system/core/init/property_patch.c
// 接着調用fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);創建一個流套接字
// listen(fd, 8); property_set_fd = fd;
// 最後在init進去無限循環中,通過socket接收其他進程的屬性請求來處理。
...
}
static int property_init_action(int nargs, char **args)
{
INFO("property init\n");
property_init();
return 0;
}
@ system/core/init/proerty_service.c
void property_init(void)
{
init_property_area();
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
// 初始了屬性區域之後,首先導入編譯生成的屬性文件:
}
@ bionic/libc/include/sys/_system_properties.h
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
@ system/core/init/proerty_service.c
#define PA_COUNT_MAX 247
#define PA_INFO_START 1024
#define PA_SIZE 32768
static workspace pa_workspace;
static prop_info *pa_info_array;
extern prop_area *__system_property_area__;
static int init_property_area(void)
{
prop_area *pa;
if(pa_info_array)
return -1;
if(init_workspace(&pa_workspace, PA_SIZE))// 初始化工作區。
return -1;
fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START);
pa = pa_workspace.data;
memset(pa, 0, PA_SIZE);
pa->magic = PROP_AREA_MAGIC;
pa->version = PROP_AREA_VERSION;
/* plug into the lib property services */
__system_property_area__ = pa;
property_area_inited = 1; // 表明屬性區已經經過了初始化。
return 0;
}
// 初始化工作區
static int init_workspace(workspace *w, size_t size)
{
void *data;
int fd;
fd = open("/dev/__properties__", O_RDWR | O_CREAT, 0600);// 以讀寫方式打開設備文件/dev/__properties__
...
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// 將該文件描述符映射到init進程用戶空間的虛擬地址,可讀可寫。
...
close(fd);
fd = open("/dev/__properties__", O_RDONLY);// 關閉之後重新已只讀打開這個設備文件。
// 這樣的打開方式保證了只有init進程有對屬性區域寫的權限,而其餘進程只有讀的權限。
unlink("/dev/__properties__");
w->data = data;
w->size = size;
w->fd = fd; // 將大小,文件描述符,虛擬地址保存在全局變量pa_workspace中。
return 0;
out:
close(fd);
return -1;
}
2. 帶socket選項的服務啓動
解析init.rc中的服務:
init_parse_config_file("/init.rc")
--> parse_config(fn, data)
--> parse_new_section(&state, kw, nargs, args)
--> parse_line_service()
...
case K_socket: {/* name type perm [ uid gid ] */
struct socketinfo *si;
if (nargs < 4) {
parse_error(state, "socket option requires name, type, perm arguments\n");
break;
}
if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
&& strcmp(args[2],"seqpacket")) {
parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
// android只支持這三種形式的socket:數據報文套接字(UDP),流套接字(TCP),seqpacket(使用SCTP協議)
break;
}
si = calloc(1, sizeof(*si)); // 分配socketinfo的內存
if (!si) {
parse_error(state, "out of memory\n");
break;
}
// installd stream 600 system system
si->name = args[1]; // installd
si->type = args[2]; // stream
si->perm = strtoul(args[3], 0, 8); // 600
if (nargs > 4)
si->uid = decode_uid(args[4]); // system
if (nargs > 5)
si->gid = decode_uid(args[5]); // system
si->next = svc->sockets;
svc->sockets = si; // 保存到當前服務中的sockets鏈表中,該服務啓動的時候會創建這些socket。
break;
}
...
開啓服務函數:service_start()
void service_start(struct service *svc, const char *dynamic_args)
{
...
NOTICE("starting '%s'\n", svc->name);
pid = fork();
if (pid == 0) {
...
if (properties_inited()) {
get_property_workspace(&fd, &sz);
sprintf(tmp, "%d,%d", dup(fd), sz);
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
}// 添加系統屬性區的描述符和大小打環境變量中,ANDROID_PROPERTY_WORKSPACE
...
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type, si->perm, si->uid, si->gid);// 創建socket
if (s >= 0) {
publish_socket(si->name, s);// 將socket添加到環境變量中
}
}
...
}
}
static void publish_socket(const char *name, int fd)
{
char key[64] = ANDROID_SOCKET_ENV_PREFIX;
char val[64];
strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
name,
sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
snprintf(val, sizeof(val), "%d", fd);
add_environment(key, val);// 添加至環境變量
/* make sure we don't close-on-exec */
fcntl(fd, F_SETFD, 0);
}