概述
int main函数
mmi.cpp
agent_main.cpp
diag_main.cpp
debug_main.cpp
misc启动进入mmi:
第一个进程:mmi mmi starting MMI_PROC_TYPE(MMI_PROC_TYPE_MMI)
第二个进程:log launch log process
第二个进程:mmi_diag Start diag daemon for handling diag command from PC tool MMI_PROC_TYPE(MMI_PROC_TYPE_MMI_DIAG);
第四个~第N个进程:mmi_agent Fork module process MMI_PROC_TYPE(MMI_PROC_TYPE_MMI_AGENT);
开始测试:switch_module
主进程的flow:
mmi.cpp
pre_config
init_config /*Initialize configuration */
post_config
init_controller /*Load controller */
build_main_ui /*Initial the MMI screen */
start_threads /*Start threads */
launch_controller /*Launch threads */
launch_clients
is_autostart /*Start Background Test */
start_autorun
sem_wait
write_file //WAKE_UNLOCK
pre_config
pre_config
parse_strings //加载各种bin执行、库、节点文件
launch_log /**start logcat process*/ fork 出一个进程来记录log
write_file //持一把wake lock,保持屏幕常亮
sem_init //初始化信号灯 g_sem_exit:mmi进程退出 g_msg_sem:同步消息的处理 g_sem_accept_ready:创建mmi_socket服务端 g_data_print_sem:sensor提示信息的打印 g_result_sem:各种RF传输外设的测试结果
pthread_mutex_init //创建互斥锁g_cur_layout_mutex 关于当前模块的layout界面
init_draw /**Init draw*/ MMI_ALOGI("start draw init!");
--> init_surface //MMI_ALOGI("start init surface");
--> sem_init //(draw_control_t) g_draw.sem 同步刷新ui界面
create_func_map //创建各种函数的调用map表
is_create_mmi_cfg //Check "/etc/mmi/mmi.xml" 等whether exist
create_mmi_cfg // parse file: "/etc/mmi/mmi.xml" 根据mmi.xml文件创建mmi.cfg // create file: "/cache/FTM_AP/mmi.cfg" mmi.cfg保存各种测试项的配置要求 ordered_ui_module module_ui_map // create file: "/cache/FTM_AP/mmi-pcba.cfg"
init_config
init_config
load_config // /cache/FTM_AP/mmi.cfg 初始化该配置文件,解析各个模块的测试要求 , 保存module_info数据到数据结构: g_ordered_modules g_modules_map
init_lang //加载语言、字体配置
init_layout // /*Load more layout */ /etc/mmi/layout/ 目录下的各种layout文件 各种layout.xml文件创建一个layout数据
--> load_layout 解析各个layout文件,并根据解析创建button等控件,保存其数据在对象layout中
g_layout_map:保存各个已经初始化后的layout对象
init_module_mode /*Initial all module running mode */ 迭代g_ordered_modules 指明所有模块的运行模式:module_info->mode = g_test_mode(ffbm-02)
init_nodup_map /*Initial the duplicate module map */ 迭代g_ordered_modules 在所有运行同一个lib库的模块中只保存最后一个数据:g_nodup_modules_map
g_res_file // /cache/FTM_AP/mmi.res 保存各种测试项的结果
post_config
post_config
restore_result /**Restore the latest result*/ g_res_file // MMI_ALOGI("start post config");
--> 根据g_res_file文件初始化各个模块的最近测试结果:module_info- >result = SUCCESS;
init_controller
init_controller
--> /* used to store diag,debug module */ < string, module_info * > g_controller_map;
new module_info(CLIENT_DIAG_NAME) /**Init Diag module*/ /**Diag control mmi commands list*/
new module_info(CLIENT_DEBUG_NAME) /**Init debug module*/
g_controller_map : CLIENT_DIAG_NAME、CLIENT_DEBUG_NAME
build_main_ui
build_main_ui
--> //MMI_ALOGI("start build main ui");
set_main_module(mod); /**Initial main module*/ 设定当前mod为主进程模块:g_main_module
write_file /**Turn on backlight*/
lay->m_listview->set_items(&g_ordered_modules); //初始化主界面main的listview
--> set_items //skip "MMI" module //skip "disabled" modules
--> m_item_per_page 一页10项
--> m_items.push_back(item);
switch_cur_layout_locked //切换当前layout为提供的模块
--> acquire_cur_layout
--> g_cur_layout = lay; g_cur_layout->module = mod;
--> release_cur_layout
register_home_screen /**register the main screen*/
--> g_home_screens.push_back(lay);
update_main_status
--> 更新主main.xml中的main_status
--> 内容:"%d P | %d F | %d L | %d R | %s %% B", pass_num, fail_num, remain_num,total_num, 电量
--> // MMI_ALOGD("pass item: %d, fail item: %d, remain item: %dn", pass_num, fail_num, remain_num);
invalidate
start_threads
start_threads
--> // MMI_ALOGI("start create threads");
create_input_threads
--> init_input /**Intial input system*/
--> pthread_mutex_init; // 创建互斥锁 runnable_mutex:没用到 g_listener_mutex:关于注册输入事件input监听
--> sem_init; // 初始化信号灯 g_sem_runable:输入事件的处理 并发调用
--> ev_init(input_callback, NULL);
--> opendir("/dev/input"); // 只打开event相关的设备文件
--> ioctl epoll_ctl /* read the evbits of the input device */
--> ev_fdinfo[ev_count].cb = input_cb;
input event回调:input_callback
* EV_SYN:- 用于事件间的分割标志。事件可能按时间或空间进行分割,就像在多点触摸协议中的例子。
* EV_KEY:- 用来描述键盘,按键或者类似键盘设备的状态变化。
* EV_REL:- 用来描述相对坐标轴上数值的变化,例如:鼠标向左方移动了5个单位。
* EV_ABS:-用来描述相对坐标轴上数值的变化,例如:描述触摸屏上坐标的值。
* EV_MSC:- 当不能匹配现有的类型时,使用该类型进行描述。
* EV_SW:- 用来描述具备两种状态的输入开关。
* EV_LED:- 用于控制设备上的LED灯的开和关。
* EV_SND:- 用来给设备输出提示声音。
* EV_REP:-用于可以自动重复的设备(autorepeating)。
* EV_FF:- 用来给输入设备发送强制回馈命令。(震动?)
* EV_PWR:- 特别用于电源开关的输入。.
* EV_FF_STATUS:- 用于接收设备的强制反馈状态。
--> ev_get_input
--> adjust_ev /**Adjust the value to match LCD resolution*/
--> hook_vkey /**Convert virtual key to KEY code*/
--> invoke_listener /**Call listener 把input event 传给监听的listener
--> EV_KEY :key_callback(ev.type, ev.code, ev.value);
EV_SW:sw_callback(ev.type, ev.code, ev.value);
EV_ABS || EV_SYN :touch_callback(&ev); --> process_touch_up
--> 触屏动作分两类:/**Button clicked*/(parse_button:onclick) /**List view item clicked*/(parse_listview:onclick)
--> enqueue_runnable_locked(&g_runnable_queue, r); //event 入列
--> get_ts_resolution // 获取触屏分辨率信息 touchscreen resolution input device name: msg22xx
--> pthread_create(&g_input_waiting_tid, NULL, input_waiting_thread, NULL);
--> ev_wait --> epoll_wait //等待之前ev_init设定的epollfd 监听事件
--> ev_dispatch --> cb(fdi->fd, polledevents[n].events, fdi->data); // cb 为input_cb (input_callback)(fd_info->cb)
--> pthread_create(&g_input_handle_tid, NULL, input_handle_thread, NULL);
--> dequeue_runnable_locked //event出列
--> r->cb(r->module); //layout.xml 中的button控件 onclick函数
pthread_create(&g_draw_tid, NULL, draw_thread, NULL);
--> acquire_cur_layout //得到当前的layout
--> draw_buttons draw_textviews draw_listviews draw_points //绘制当前layout的ui界面
pthread_create(&g_accept_tid, NULL, server_accepting_thread, NULL);
--> mkdir :/dev/socket/
--> create_socket:/dev/socket/mmi
--> listen
--> sem_post; //g_sem_accept_ready
--> accept //等待客户端的请求 KEY_MMI_SOCKET //client_fd
--> // 等待客户端连接请求,在没有客户端连接请求到来之前,* 程序会一直阻塞在这个函数里
--> //已经接受客户端连接请求,accept()函数创建并返回了一个* 新的套接字client_fd,用于与客户端通信。
--> /* 发送数据到客户端 */send(client_fd, data); /* 从客户端接收数据 */recv(client_fd, data);
--> recv(client_fd, &msg, sizeof(msg), MSG_WAITALL)
--> // MMI_ALOGI("connect success for module=[%s], cmd=%s, subcmd=%s, socdetFd=%dn",msg.module, MMI_CMD_NAME(msg.cmd), MMI_STR(msg.subcmd), client_fd);
--> module_set_fd(msg.module, client_fd); /**set the module fd*/ /*Set to module */
--> mod->socket_fd = fd;
--> g_clients.push_back(mi);
--> static list < module_info * >g_clients; /* used for clients that launched successfully;Its content is part of g_modules*/
pthread_create(&g_waiting_event_tid, NULL, msg_waiting_thread, NULL);
--> //MMI_ALOGI("thread(msg_waiting_thread) startedn");
--> msg_waiting
--> //g_clients.empty() // MMI_ALOGW("wait for client connection...n");
//g_clients : 已经启动的模块
--> select(g_max_fd + 1, &fds, NULL, NULL, &tv); // select()调用返回处于就绪状态并且已经包含在fd_set(fds)结构中的描述字总数
--> recv(fd, msg, sizeof(msg_t), MSG_WAITALL) //读取客户端 发来的消息message请求
--> //MMI_ALOGI("mmi recv msg: moduld=[%s], cmd=%s, subcmd=%s, msg_id=%s, msg=%s, msg_size=%d, result=%sn",msg->module, MMI_CMD_NAME(msg->cmd), MMI_STR(msg->subcmd), MMI_PRI_TYPE(msg->msg_id),MMI_STR(msg->msg), msg->length, MMI_RESULT(msg->result));
--> enqueue_msg //消息message的入列 // g_msg_queue
--> sem_post //g_msg_sem // 通知消息message入列
pthread_create(&g_msg_handle_tid, NULL, msg_handle_thread, NULL);
--> // MMI_ALOGI("thread(msg_handle_thread) startedn");
--> sem_wait(); //g_msg_sem 等待消息message的入列
--> dequeue_msg //消息message的出列 // g_msg_queue
--> //根据消息msg->cmd指令类型调用相应的函数
case CMD_CTRL:handle_ctr_msg(msg, mod);
case CMD_PRINT:handle_print(msg, mod);
case CMD_QUERY:handle_query(msg, mod);
case CMD_RUN:handle_run(msg, mod);
sem_wait(); // 等待线程server_accepting_thread的开启server g_sem_accept_ready
launch_controller
launch_controller
--> //Start diag daemon for handling diag command from PC tool
--> /system/bin/mmi_diag diag process
--> fork execv //fork 出一个进程来执行来自PC端的指令操作
--> diag_main.cpp
--> //MMI_PROC_TYPE(MMI_PROC_TYPE_MMI_DIAG);
launch_clients
launch_clients
--> /* Launch clients */
--> fork_launch_module //g_nodup_modules_map /**Fork module process*/ 加载lib库,相当于加载HAL层 /* Launch clients */
--> //MMI_ALOGI("fork '%s' for module:[%s]", agent, mod->module);
--> fork execv // bin:/system/bin/mmi_agent32 (对应agent_main.cpp) // 参数:("-m", mod->module, "-p", para) lib_path + parameter
--> agent_main.cpp
--> //MMI_PROC_TYPE(MMI_PROC_TYPE_MMI_AGENT);
--> //MMI_ALOGD("mmi_agent process pid=%d for module:[%s]n", pid, mod->module);
第四个~第N个进程的flow:
agent_main.cpp
agent_main.cpp
--> sem_init //g_msg_sem
--> parse_strings /** Initial path config from xml file*/
--> //MMI_ALOGI("start mmi_agent for module:[%s]", g_module_name);
--> load_module(lib_path, &g_module);
--> //MMI_ALOGI("start connect to server for module:[%s]", g_module_name);
--> connect_server(get_value(KEY_MMI_SOCKET)); /** Connect to MMI server via socket*/ //KEY_MMI_SOCKET --> --> (server_accepting_thread)accept
--> say_hello(g_sock, g_module_name); /**Ready, say hello to server*/ //CMD_HELLO --> (server_accepting_thread)recv
--> g_module->methods->module_init(g_module, module_params); /** Call initialize function when module start*/
--> module_init //MMI_MODULE_INFO_SYM // module init
--> pthread_create(&pid_wait, NULL, msg_waiting_thread, &g_sock);
--> //Receive thread handle function
--> //MMI_ALOGI("thread(msg_waiting_thread) start for module:[%s]", g_module_name);
--> recv(sock, msg, sizeof(msg_t), MSG_WAITALL) /** Receive a reply from the MMI server */
--> //MMI_ALOGI("from mmi recv msg: moduld=[%s], cmd=%s, subcmd=%s, msg=%s, msg_size=%dn",msg->module, MMI_CMD_NAME(msg->cmd), MMI_STR(msg->subcmd), MMI_STR(msg->msg), msg->length);
--> enqueue_msg(&g_msg_queue, msg); //服务端request的入列 /** Enquenue the request which handled in a single thread*/
--> sem_post(); //g_msg_sem 通知服务端message入列 /**Notify the handle thread*/
--> pthread_create(&pid_handle, NULL, msg_handle_thread, NULL);
--> //Handle message thread to read message from pending message queue
--> //MMI_ALOGI("thread(msg_handle_thread) start for module:[%s]", g_module_name);
--> sem_wait(); //g_msg_sem 等待服务端message入列
--> dequeue_msg(&g_msg_queue, &msg);//服务端request的出列
--> pthread_create(&ptid, NULL, msg_process_thread, msg); /**Start one single thread for each request */
--> //msg_process_thread
--> //MMI_ALOGI("process msg: moduld=[%s], cmd=%s, subcmd=%s, msg=%s, msg_size=%d",preq->module, MMI_CMD_NAME(preq->cmd), MMI_STR(preq->subcmd), MMI_STR(preq->msg), preq->length);
--> //根据消息preq->cmd指令类型调用相应的函数
case CMD_INIT:ret = handle_init(g_module, preq, &resp);
case CMD_DEINIT:ret = handle_deinit(g_module, preq, &resp);
case CMD_QUERY:ret = handle_query(g_module, preq, &resp);
case CMD_RUN:ret = handle_run(g_module, preq, &resp);
case CMD_STOP:ret = handle_stop(g_module, preq, &resp);
--> send_msg(g_sock, &resp); //反馈resp回服务端serve
--> pthread_join(pid_wait, NULL);
--> pthread_join(pid_handle, NULL);
--> //pthread_join()函数会一直阻塞调用线程,直到指定的线程tid终止
--> exi
switch_module
switch_module
--> //MMI_ALOGI("get cur layout(%s) for module:[%s]", mod->config_list[KEY_LAYOUT].c_str(), mod->module);
--> switch_cur_layout_locked(lay, mod);
--> //主界面 :update_main_status
--> initial_screen(mod);
--> module_exec_ui(mod);
--> pthread_create(&g_module_tid, NULL, launch_module, (void *) mod);
--> //MMI_ALOGI("launch module:[%s] testingn", mod->module);
--> send_run_mmi(mod);
--> send_cmd(mod, CMD_RUN, SUBCMD_MMI); /** RUN MMI */ (/** send a request to the module client */) --> msg_waiting_thread(/** Receive a reply from the MMI server */) --> msg_process_thread : handle_run --> module->methods->module_run(module, req->subcmd, params);
--> //MMI_ALOGD("create thread(thread id=%lu) for module:[%s] test", g_module_tid, mod->module);
--> invalidate
最后
以上就是无辜黑猫为你收集整理的fastmmi flow and framework的全部内容,希望文章能够帮你解决fastmmi flow and framework所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复