fastmmi flow and framework

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lf12345678910/article/details/78873462

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: %d\n", 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=%d\n",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) started\n");
              -->  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=%s\n",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) started\n");
              -->  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=%d\n",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] testing\n", 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


 

猜你喜欢

转载自blog.csdn.net/lf12345678910/article/details/78873462