1. 程式人生 > >Qualcomm平臺qcril初始化及訊息處理流程(原)

Qualcomm平臺qcril初始化及訊息處理流程(原)

        本節主要來介紹Qcril的初始化流程以及訊息在Qcril中如何傳遞。

        Android平臺不同廠商的AP側可以相同,但是Modem側肯定會有很大的差異,RIL層要解決一個問題就是適配不同廠商的Modem,為了達到相容性要求,Android在AP與Modem之間搭建了RILC的框架,由不同的Modem廠商將自己的協議連線到AP側。對於高通平臺來說,他的RILC就是QCRIL

        在Qcril中儲存一個靜態表單,裡面儲存了所有RILC中下發請求的ID以及相應的處理函式,表單內容簡要如下:
        static qcril_dispatch_table_entry_type qcril_event_table[] = {
            /* QCRIL_EVT_UIM_QMI_COMMAND_CALLBACK */
            { QCRIL_REG_ALL_STATES( QCRIL_EVT_UIM_QMI_COMMAND_CALLBACK, qcril_uim_process_qmi_callback ) },
            /* QCRIL_EVT_UIM_QMI_INDICATION */
            { QCRIL_REG_ALL_STATES( QCRIL_EVT_UIM_QMI_INDICATION, qcril_uim_process_qmi_indication ) },
            /* QCRIL_EVT_INTERNAL_UIM_VERIFY_PIN_COMMAND_CALLBACK */
            { QCRIL_REG_ALL_STATES( QCRIL_EVT_INTERNAL_UIM_VERIFY_PIN_COMMAND_CALLBACK, qcril_uim_process_internal_command ) },
            /* QCRIL_EVT_INTERNAL_MMGSDI_CARD_POWER_UP */
            { QCRIL_REG_ALL_STATES( QCRIL_EVT_INTERNAL_MMGSDI_CARD_POWER_UP, qcril_uim_process_internal_command ) },
            /* 0x90007 - QCRIL_EVT_HOOK_OEM_ENG_MODE   */
            { QCRIL_REG_ALL_ACTIVE_STATES( QCRIL_EVT_HOOK_OEM_ENG_MODE, qcril_qmi_nas_request_eng_mode_info ) },
            /* 1 - RIL_REQUEST_GET_SIM_STATUS */
            { QCRIL_REG_ALL_ACTIVE_STATES( RIL_REQUEST_GET_SIM_STATUS, qcril_uim_request_get_sim_status ) },
            /* 2 - RIL_REQUEST_ENTER_SIM_PIN */
            { QCRIL_REG_ALL_ACTIVE_STATES( RIL_REQUEST_ENTER_SIM_PIN, qcril_uim_request_enter_pin ) },
            /* 105 - RIL_REQUEST_ISIM_AUTHENTICATION */
            { QCRIL_REG_ALL_ACTIVE_STATES( RIL_REQUEST_ISIM_AUTHENTICATION, qcril_uim_request_isim_authenticate ) },
        }
        裡面每一項都包含兩個元素:事件ID和處理函式,在處理這些訊息時將會根據事件的ID查詢並執行相應的處理函式。

        比如,對於得到當前SIM卡狀態這個請求,對應的ID為RIL_REQUEST_GET_SIM_STATUS,而其處理函式為:qcril_uim_request_get_sim_status()

一、Qcril初始化流程

        初始化流程需要完成EventLoop訊息迴圈的建立、各個模組的初始化等工作。先看RILD部分。
        @rild.c
        int main(int argc, char **argv)
        {
            //動態載入reference-ril.so或者qcril.so
            dlHandle = dlopen(rilLibPath, RTLD_NOW);
            //建立Loop監聽Socket事件
            RIL_startEventLoop();
            rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
            funcs = rilInit(&s_rilEnv, argc, rilArgv);
            RIL_register(funcs);
        }
        在RILD中會通過dlsym查詢ril庫中的RIL_Init函式地址,然後通過rilInit呼叫,對高通來說,該函式在qcril.c中:
        @qcril.c
        const RIL_RadioFunctions *RIL_Init ( const struct RIL_Env *env, int argc, char **argv) {
            //設定執行緒名字為rild
            qmi_ril_set_thread_name( pthread_self() , QMI_RIL_QMI_RILD_THREAD_NAME);
            qmi_ril_fw_android_request_flow_control_init();
            //初始化unsol的eventlist pending_unsol_resp_list,為其分配記憶體
            qmi_ril_init_android_unsol_resp_pending_list();
            //初始化接收Modem訊息的EventLoop
            qcril_event_init();
            //初始化qcril中的各個模組
            qcril_init();
            //開啟EventLoop
            qcril_event_start();
            //其他初始化
            qmi_ril_initiate_bootup();
            //返回RILD對RILC的介面函式
            return &qcril_request_api[ QCRIL_DEFAULT_INSTANCE_ID ];
        }

        下面我們分別來分析上面的過程。

1.1、初始化EventLoop過程

        在Qcril中搭建了EventLoop迴圈用於檢測Modem上報的訊息,而EventLoop機制的初始化工作是在qcril_event_init()中完成的。
        @qcril_event.c
        void qcril_event_init( void ) {
            pthread_attr_t attr;
            int ret;
            qcril_event.started = 0;
#ifdef QMI_RIL_UTF
            pthread_attr_init (&attr);
            ret = utf_pthread_create_handler(&qcril_event.tid, &attr, qcril_event_main, NULL);
            pthread_attr_destroy( &attr );
#else
            pthread_attr_init (&attr);
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
            //建立EventLoop執行緒,執行緒入口是qcril_event_main
            ret = pthread_create(&qcril_event.tid, &attr, qcril_event_main, NULL);
            pthread_attr_destroy( &attr );
#endif
            //設定執行緒名字為"event"
            qmi_ril_set_thread_name(qcril_event.tid, QMI_RIL_EVENT_THREAD_NAME);
            pthread_mutexattr_init( &qcril_event.activity_lock_mutex_atr );
            pthread_mutex_init( &qcril_event.activity_lock_mutex, &qcril_event.activity_lock_mutex_atr );
            while (qcril_event.started == 0)
            {
                pthread_cond_wait(&qcril_event_startupCond, &qcril_event.startup_mutex);
            }
        }
        在初始化過程中,通過pthread_create()函式建立了EventLoop執行緒,並且指出該執行緒的入口函式為qcril_event_main(),我們從執行緒的入口開始分析:
        static void *qcril_event_main ( void *param) {
            int ret;
            int filedes[2];
            int n;
            fd_set rfds;
            qcril_event_type *ev;
            char buff[16];
            IxErrnoType err_no;
            int go_on;


            param = param;
            pthread_mutex_init(&qcril_event.list_mutex, NULL);
            //初始化qcril_event.list連結串列
            qcril_event_init_list(&qcril_event.list);
            FD_ZERO(&qcril_event.readFds); /* Needed to use select() system call */
            QCRIL_MUTEX_LOCK( &qcril_event.startup_mutex, "[Event Thread] qcril_event.startup_mutex" );
            qcril_event.started = 1;
            //建立管道
            ret = pipe(filedes);
            qcril_event.fdWakeupRead = filedes[0];
            qcril_event.fdWakeupWrite = filedes[1];


            fcntl(qcril_event.fdWakeupRead, F_SETFL, O_NONBLOCK);
            FD_SET(qcril_event.fdWakeupRead, &qcril_event.readFds);
            pthread_cond_broadcast(&qcril_event_startupCond);
            while (qcril_event.started < 2)
            {
                //阻塞等待qcril初始化
                pthread_cond_wait(&qcril_event_startupCond, &qcril_event.startup_mutex);
            }


            for (;;)
            {
                /* Make a local copy of read fd_set;  Don't ask why. */
                memcpy(&rfds, &qcril_event.readFds, sizeof(fd_set));
                //阻塞等待接收內容
                n = select(qcril_event.fdWakeupRead + 1, &rfds, NULL, NULL, NULL);
                if (n < 0)
                {
                    if (errno == EINTR) continue;
                    QCRIL_LOG_ERROR("QCRIL event select error (%d)", errno);
                    qmi_ril_clear_thread_name(pthread_self());
                    return NULL;
                }
                /* Empty the socket */
                do
                {
                    //讀取內容
                    ret = read(qcril_event.fdWakeupRead, &buff, sizeof(buff));
                } while (ret > 0 || (ret < 0 && errno == EINTR));
                do
                {
                    if ( ( NULL != ( ev = qcril_event.list.next ) && ( ev != &qcril_event.list ) ) )
                    {
                        qcril_event_remove_from_list( ev );
                        QCRIL_MUTEX_UNLOCK( &qcril_event.list_mutex, "[Event Thread] qcril_event.list_mutex" );
                        //處理Modem傳送的請求
                        err_no = qcril_process_event( ev->instance_id, ev->modem_id, ev->event_id, ev->data, ev->datalen, ev->t );
                        QCRIL_MUTEX_LOCK( &qcril_event.list_mutex, "[Event Thread] qcril_event.list_mutex" );
                        if ( ev->data_must_be_freed && ev->data )
                        {
                            qcril_free( ev->data );
                        }
                        qcril_free( ev );
                    }
                    go_on = ( ( NULL != ( ev = qcril_event.list.next ) && ( ev != &qcril_event.list ) ) );
                } while ( go_on );


            }
            qmi_ril_clear_thread_name(pthread_self());
            return NULL;
        }
        在以上過程中,完成qcril_event.list連結串列的初始化,然後通過pthread_cond_wait進入阻塞狀態,當被解鎖後以及進入EventLoop迴圈,檢測到事件後,通過qcril_process_event處理。

1.2、初始化qcril各個模組

        Qcril在接到RILC的請求後,需要根據請求的型別將訊息派發給不同的負責模組,而qcril_init()就是完成各個模組的初始化工作。
        void qcril_init ( void) {
            qcril_arb_init();
            qcril_init_state();
            qmi_ril_oem_hook_init();
            qcril_db_init();
            //初始化Event table
            qcril_init_hash_table();
            qcril_reqlist_init();
#ifdef FEATURE_QCRIL_PLMN_LIST
            qcril_qmi_nas2_init();
#endif
            qcril_request_suppress_list_init();
            qmi_ril_qmi_client_pre_initialization_init();
            qmi_ril_qmi_client_pre_initialization_acquire();
            qcril_qmi_nas_dms_commmon_pre_init();
            qcril_qmi_voice_pre_init();
#ifndef QMI_RIL_UTF
            qcril_am_pre_init();
#else
            qmi_ril_rat_enable_option = QMI_RIL_FTR_RAT_UNKNOWN;
            qmi_ril_baseband_ftr_info = QMI_RIL_FTR_BASEBAND_UNKNOWN;
#endif
            qcril_qmi_imsa_pre_init();
            qcril_qmi_sms_pre_init();
            QCRIL_LOG_FUNC_RETURN();
        }
        在這裡對qcril的各個模組進行初始化。其中完成了很重要的一步就是將qcril_event_table表拷貝給qcril_hash_table,用於onRequest時對各種請求進行處理,我們來看具體操作:
        static void qcril_init_hash_table( void ) {
            uint32 reg_index, hash_index; /*!< index into hash table */
            qcril_dispatch_table_entry_type *temp_entry_ptr;
            for (reg_index = 0; reg_index < QCRIL_ARR_SIZE( qcril_event_table ); reg_index++)
            {
                hash_index = qcril_hash( qcril_event_table[reg_index].event_id, QCRIL_HT_ENTRIES_MAX, 0 );
                if(hash_index < QCRIL_HT_ENTRIES_MAX)
                {
                    if (qcril_hash_table[hash_index] == NULL)
                    {
                        //將qcril_event_table拷貝給qcril_hash_table
                        qcril_hash_table[hash_index] = &qcril_event_table[reg_index];
                    }
                    else
                    {
                        temp_entry_ptr = qcril_hash_table[hash_index];
                        while (temp_entry_ptr->next_ptr != NULL)
                        {
                            temp_entry_ptr = temp_entry_ptr->next_ptr;
                        }
                        temp_entry_ptr->next_ptr = &qcril_event_table[reg_index];
                    }
                }
            }
        }

        經過上面的拷貝,qcril_event_table中就儲存了所有Request的id和處理方法。

1.3、開啟EventLoop

        在1.1中介紹過,初始化EventLoop時,在完成其連結串列的初始化過程後,通過pthread_cond_wait()將其阻塞,而現在要做的就是取消其阻塞狀態,使其進入訊息檢測迴圈。
        這是在qcril_event_start()中完成的:
        void qcril_event_start( void )
        {
            QCRIL_MUTEX_LOCK( &qcril_event.startup_mutex, "[Main Thread] qcril_event.startup_mutex" );
            //更新狀態
            qcril_event.started = 2;
            //釋放EventLoop鎖
            pthread_cond_broadcast(&qcril_event_startupCond);
            QCRIL_MUTEX_UNLOCK( &qcril_event.startup_mutex, "[Main Thread] qcril_event.startup_mutex" );


        }

        由於EventLoop被初始化後一直處於阻塞狀態,所以在這裡將started狀態置為2後,對qcril_event_startupCond進行解鎖,從而使EventLoop進入迴圈。

1.4、其他初始化過程

        在qmi_ril_initiate_bootup()中完成了一些其他的初始化流程。

        void qmi_ril_initiate_bootup(void)
        {
              qcril_setup_timed_callback( QCRIL_DEFAULT_INSTANCE_ID, QCRIL_DEFAULT_MODEM_ID, qmi_ril_bootup_perform_core_or_start_polling, NULL, NULL );
        }
        繼續看qmi_ril_bootup_perform_core_or_start_polling()過程:
        void qmi_ril_bootup_perform_core_or_start_polling(void * params)
        {
            RIL_Errno init_res;
            int ril_version;
            qcril_unsol_resp_params_type unsol_resp;
            qmi_ril_main_thread_id = pthread_self();
            qmi_ril_set_thread_name( qmi_ril_fw_get_main_thread_id(), QMI_RIL_QMI_MAIN_THREAD_NAME);
            qmi_ril_wave_modem_status(); // this should result in "modem unavailble" report
            qmi_ril_set_operational_status( QMI_RIL_GEN_OPERATIONAL_STATUS_INIT_PENDING ); // for consistency
            qmi_ril_set_operational_status( QMI_RIL_GEN_OPERATIONAL_STATUS_INIT_ONGOING );
            //qmi初始化
            init_res = qmi_ril_core_init();
        }
        上面通過qmi_ril_core_init()完成了qmi的初始化:
        RIL_Errno qmi_ril_core_init(void)
        {
            RIL_Errno res = RIL_E_GENERIC_FAILURE;
            QCRIL_LOG_FUNC_ENTRY();
            qcril_event_suspend(); // to ensure atomic init flow cross sub domains
            do
            {
                //qcril client的初始化
                res = qcril_qmi_client_init();
                if ( RIL_E_SUCCESS != res )
                    break;
                qcril_other_init();
                qcril_uim_init();
                qcril_gstk_qmi_init();
#ifndef QMI_RIL_UTF
                qcril_data_init();
#endif
                qcril_qmi_nas_dms_commmon_post_init();
                if (qmi_ril_is_feature_supported(QMI_RIL_FEATURE_OEM_SOCKET))
                {
                    QCRIL_LOG_INFO( "%s Init OEM socket thread", __FUNCTION__ );
                    qcril_qmi_oem_socket_init();
                }


            } while (FALSE);
            qcril_event_resume();
            QCRIL_LOG_FUNC_RETURN_WITH_RET(res);
            return res;
        }
        在上面完成了qcril客戶端的初始化過程:
        RIL_Errno qcril_qmi_client_init( void )
        {
            qmi_client_error_type client_err = 0;
            RIL_Errno res = RIL_E_GENERIC_FAILURE;
            QCRIL_LOG_FUNC_ENTRY();
            /* Start modem or vote for start modem */
            qcril_qmi_modem_power_process_bootup();
            memset(&client_info, 0, sizeof(client_info));
            do
            {


                // QMI VOICE command callback
                client_info.client_cbs[QCRIL_QMI_CLIENT_VOICE] = qcril_qmi_voice_command_cb;


                // Get IDL service objects
                client_info.service_objects[QCRIL_QMI_CLIENT_VOICE] = voice_get_service_object_v02();
                client_info.service_objects[QCRIL_QMI_CLIENT_NAS] = nas_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_WMS] = wms_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_WDS] = wds_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_DMS] = dms_get_service_object_v01();
                /*client_info.service_objects[QCRIL_QMI_CLIENT_UIM] = uim_get_service_object_v01();*/
                client_info.service_objects[QCRIL_QMI_CLIENT_PBM] =  pbm_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_RF_SAR] =  sar_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_IMS_VT] =   ims_qmi_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_IMS_PRESENCE] = imsp_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_IMSA] = imsa_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_RFPE] = rfrpe_get_service_object_v01();
                client_info.service_objects[QCRIL_QMI_CLIENT_IMS_SETTING] = imss_get_service_object_v01();
                if ( qmi_ril_get_process_instance_id() == QCRIL_DEFAULT_INSTANCE_ID )
                {
                    client_info.service_objects[QCRIL_QMI_CLIENT_PDC] = pdc_get_service_object_v01();
                }


                pthread_mutexattr_init(&client_info.cache_lock_mtx_atr);
                pthread_mutex_init(&client_info.cache_lock_mutex, &client_info.cache_lock_mtx_atr);
                res = qcril_qmi_init_core_client_handles();
                if (RIL_E_SUCCESS != res)
                    break;


            } while (FALSE);
            return res;
        }

1.5、將回調函式註冊給RILC

        在Qcril的初始化完畢後,將自己的函式列表返回給RilC,也就是qcril_request_api:
        static const RIL_RadioFunctions qcril_request_api[] = {
              { RIL_VERSION, onRequest_rid, currentState_rid, onSupports_rid, onCancel_rid, getVersion_rid }
        };
        這樣的話,在RIL中呼叫的介面就會進入該函式列表中進行處理。

        以上就是qcril的初始化流程。

二、QCRIL對請求的處理過程

        當ril有請求過來時,就會呼叫ril庫的onRequest()方法,此時就會根據當前Qcril註冊的函式列表進入到qcril_request_api的onRequest_rid()函式中:
        @qcril.c
        static void onRequest_rid ( int request, void *data, size_t datalen, RIL_Token t)
        {
            onRequest( qmi_ril_process_instance_id, request, data, datalen, t );
        }
        然後進入onRequest()中繼續處理:
        static void onRequest ( qcril_instance_id_e_type  instance_id, int request, void *data, size_t datalen, RIL_Token t) {
            udit_result = qmi_ril_fw_android_request_render_execution( param.t,
                    param.event_id,
                    param.data,
                    param.datalen,
                    param.instance_id,
                    &log_dispatch_dedicated_thrd );
        }
        繼續:
        RIL_Errno qmi_ril_fw_android_request_render_execution( RIL_Token token, int android_request_id, void * android_request_data, int android_request_data_len, qcril_instance_id_e_type  instance_id, int * is_dedicated_thread ) {
            do
            {
                entry_ptr = NULL;
                //從hash表中查詢當前的Event
                if ( qcril_hash_table_lookup( (uint32) param.event_id, &entry_ptr ) != E_SUCCESS || NULL == entry_ptr )
                {
                    audit_result = RIL_E_REQUEST_NOT_SUPPORTED;
                    break;
                }
                if ( dedicated_thrd_req_lookup_val == param.event_id )
                { // deferred thread exec
                }
                else
                {
                    //派發該Event
                    if ( qcril_dispatch_event( entry_ptr, ¶m ) == E_NOT_ALLOWED )
                    {
                        audit_result = RIL_E_RADIO_NOT_AVAILABLE;
                        break;
                    }
                }
            } while (FALSE);
            return audit_result;
        }
        在上面的過程中,要先通過qcril_hash_table_lookup()函式查詢當前的Event,如果沒有找到當前的Request,就認為非法,找到之後,進入qcril_dispatch_event()中派發該Event:
        IxErrnoType qcril_dispatch_event ( qcril_dispatch_table_entry_type *entry_ptr, qcril_request_params_type *params_ptr) {
            if(params_ptr != NULL && (params_ptr->instance_id < QCRIL_MAX_INSTANCE_ID) )
            {
                // print the recieved date byte stream
                qcril_qmi_print_hex(params_ptr->data,  params_ptr->datalen);
                instance_id = params_ptr->instance_id;
                s_ptr = &qcril_state->info[ instance_id ];
                modem_id = params_ptr->modem_id;
                if (E_SUCCESS == res)
                {
                    //處理當前Request
                    (entry_ptr->handler)(params_ptr, &ret);
                    if ( ret.pri_gw_sim_state_changed || ret.pri_cdma_sim_state_changed ||
                            ret.sec_gw_sim_state_changed || ret.sec_cdma_sim_state_changed ||
                            ret.ter_gw_sim_state_changed || ret.ter_cdma_sim_state_changed
                       )
                    {
                        qcril_state_transition( instance_id, modem_id, params_ptr->event_id, &ret );
                    }
                }
            }
            else
            {
            }
            return res;
        }
        上面的過程通過entry_ptr->handler呼叫當前Event的處理函式。這裡的handler對應qcril_hash_table中的某一項。從上面1.2步驟中我們將qcril_event_table表中的資料拷貝給了qcril_hash_table,所以這裡的handler可以理解為qcril_event_table中的某一項。
        之後的流程就會進入到某個具體請求的處理函式中,比如對於得到當前SIM卡狀態這個請求,其處理函式為:qcril_uim_request_get_sim_status()。

相關推薦

Qualcomm平臺qcril初始訊息處理流程

        本節主要來介紹Qcril的初始化流程以及訊息在Qcril中如何傳遞。         Android平臺不同廠商的AP側可以相同,但是Modem側肯定會有很大的差異,RIL層要解決一個問題就是適配不同廠商的Modem,為了達到相容性要求,Android在AP

Qualcomm平臺qcril初始訊息處理流程

        Android平臺不同廠商的AP側可以相同,但是Modem側肯定會有很大的差異,RIL層要解決一個問題就是適配不同廠商的Modem,為了達到相容性要求,Android在AP與Modem之間搭建了RILC的框架,由不同的Modem廠商將自己的協議連線到AP側。對於高通平臺來說,他的RILC就

Servlet和SpringMVC的初始請求處理過程淺析

Servlet是一套Web應用的開發規範,我們按照這套規範編碼就可以實現一個Web應用,使其在Web容器中執行。 我們最開始學習J2EE時,學習和建立的就是Servlet的實現類,後來學習了MVC框架以後,尤其是SpringMVC,就很少直接建立Servlet

SD卡初始讀寫流程

SD卡除錯關鍵點: 1.      上電時要延時足夠長的時間給SD卡一個準備過程,在我的程式裡是5秒,根據不同的卡設定不同的延時時間。SD卡初始化第一步在傳送CMD命令之前,在片選有效的情況下首先要傳送至少74個時鐘,否則將有可能出現SD卡不能初始化的問題。 2.      SD卡傳送復位命令CMD0

Netty:基礎概念訊息處理流程

1.  Netty是什麼?   Netty是由JBOSS提供的一個java開源網路通訊框架。Netty可以提供非同步的,非阻塞的,事件驅動的網路應用程式框架和工具,非常適合用來快速開發高效能、高可靠

[PyTorch]PyTorch中模型的參數初始的幾種方法

plane alt align frame nor view tps class normal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~本文目錄1. xavier初始化2. kaiming初始化3. 實際使用中看到的初始化3.1 ResN

Android之訊息處理機制Handler的本質-Message和Looper到底是什麼?

目錄 Android之訊息處理機制(二) 以下皆為乾貨,比較幹,需要讀者細細理解。  前面(一)已經解釋了Handler的基本機制了,下面來概括一下本質。 一、MessageQueue        MessageQueue其實就

Android架構分析之Android訊息處理機制

作者:劉昊昱  Android版本:4.4.2 在上一篇文章中我們看了一個使用Handler處理Message訊息的例子,本文我們來分析一下其背後隱藏的Android訊息處理機制。 我們可能比較熟悉Windows作業系統的訊息處理模型: while(GetMessage

Android架構分析之Android訊息處理機制

作者:劉昊昱  Android版本:4.4.2 本文我們來分析AndroidUI執行緒即主執行緒是怎樣實現對訊息的處理的。 UI執行緒的實現類定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中。

初始與清理之二清理

前言 初始化往往是程式設計師呼叫方法前所必須做的事情,但物件用完之後的清理卻常常忽略。對於清理,java中提供了垃圾回收器機制,通常情況下不必由程式設計師關心如何清理的問題;垃圾回收機制在便利的同時也引發兩個問題:一是垃圾回收器只能回收由new分配的記憶體空間

資料歸一三種方法python

資料標準化(歸一化)處理是資料探勘的一項基礎工作,不同評價指標往往具有不同的量綱和量綱單位,這樣的情況會影響到資料分析的結果,為了消除指標之間的量綱影響,需要進行資料標準化處理,以解決資料指標之間的可比性。原始資料經過資料標準化處理後,各指標處於同一數量級,適合進行綜合對比評價。以下是三種常用的歸一化方法:m

coding git 初始與專案遠端連線

git 的安裝與配置 一.git簡介 Git是一款免費、開源的分散式版本控制系統。git 的速度很快,對於我們做一些很大的專案來說就方便了很多。 二.git 的下載與安裝 下載地址:https://git-scm.com/download

Netty原始碼分析--初始Options,新增處理器

接上篇,我們繼續進入AbstractBootstrap類的 initAndRegister() 方法 進入init()方法 設定父級Channel的options, 進入到上節提到的NioServerSocketChannelConfig 其實就是為我們的cha

IPv6實現--傳入包的處理流程1

IPv6中資料包的接收處理流程 在一個IPSEC包進入到網路層呼叫~/net/ipv6/ip6_input.c中的ipv6_rcv()函式,然後進入第一個鉤子NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, dev, NULL,ip6_r

Java內存管理-初始JVM和JVM啟動流程

mac 指令 關系圖 java虛擬機 隔離 hibernate 不同 物理 計算 勿在流沙住高臺,出來混遲早要還的。 做一個積極的人 編碼、改bug、提升自己 我有一個樂園,面向編程,春暖花開! 上一篇分享了什麽是程序,以及Java程序運行的三個階段。也順便

Tomcat 第四篇:請求處理流程

![](https://cdn.geekdigging.com/java/tomcat/tomcat_header.jpg) ## 1. 引言 既然是在講 Tomcat ,那麼一個 HTTP 請求的請求流程是無論如何也繞不開的。 首先拋開所有,使用我們現有的知識面,猜測一下一個請求被 Tomcat 處

Tomcat 第五篇:請求處理流程

![](https://cdn.geekdigging.com/java/tomcat/tomcat_header.jpg) ## 1. 請求處理流程 AprEndPoint 順著上一篇接著聊,當一個請求傳送到 Tomcat 以後,會由聯結器 `Connector` 轉送至 `AprEndPoint` ,

Servlet初始處理HTTP請求

png cal 共享 servlet配置 用戶訪問 input 端口號 doget 本地 上一篇詳細介紹了與Servlet相關的幾個核心的接口和類,當我們自己寫Servlet類時,一般需要繼承HttpServlet類,實現init()、doGet()、doP

CentOS7系統環境初始安裝的時候網卡改名為eth*

ati cfg iyu ios tcpdump log sysconfig emctl 更新 操作系統安裝: 將網卡名稱設置為eth*,不使用CentOS 7默認的網卡命名規則。所以需要在安裝的時候,增加內核參數。1. 光標選擇“Install CentOS 7”

Web開發中Listener、Filter、Servlet的初始調用

children tomcat啟動 什麽 lis exceptio try 部分 OS findchild 我們在使用Spring+SpringMVC開發項目中,web.xml中一般的配置如下: 1 <?xml version="1.0" encoding=