Android4.4 RIL的AT命令增加流程

首先,感謝http://blog.csdn.net/guoleimail/article/details/41649537這篇博文的出現,文中不僅列出了大部分要修改的代碼,還給出了原理闡述。本文作爲該博文的補充,將所有修改的地方全部給出,由上層應用逐級往下調用,但類之間的關係不作說明,想弄清楚的朋友可以看看下面的鏈接

http://blog.csdn.net/youbang321/article/details/7803023
http://www.elexcon.com/news/54715.html
http://blog.csdn.net/arnoldlu/article/details/9189939
http://blog.sina.com.cn/s/blog_682793a50100jeo5.html
http://www.cnblogs.com/jesse123/p/3167519.html
http://www.redwolf-blog.com/?p=966
http://yelinsen.iteye.com/blog/848137
http://yelinsen.iteye.com/blog/848129
http://blog.163.com/fengxuedong_fxd/blog/static/71926306201181933443646/
http://blog.csdn.net/forlong401/article/details/5403379


frameworks\base\telephony\java\android\telephony\TelephonyManager.java

在尾部增加

	   /**
    * Send AT command via sync tunnel, it should return result until the command execute completely.
    * @param cmd  AT command
    * @param time max time for executing at command, unit is ms.
    * return is result of AT.
    */
    public String AtCommandSendSync(String cmd, int time){
        try {
            return getITelephony().AtCommandSendSync(cmd, time);
        } catch (RemoteException ex) {
            return null;
        } catch (NullPointerException ex) {
            return null;
        }
    }

        /**
     * Send AT command via unsync tunnel, it should return true or false when AT command has been send.
     * @param cmd AT command
     * return boolean
     */
    public boolean AtCommandSendUnSync(String cmd){
        try {
            return getITelephony().AtCommandSendUnSync(cmd);
        } catch (RemoteException ex) {
            return false;
        } catch (NullPointerException ex) {
            return false;
        }
    }


frameworks\base\telephony\java\com\android\internal\telephony\ITelephony.aidl

在尾部增加

/**
	 * Execute AT command via unsync tunnel
	 * @param cmd AT command to execute
	 * execute successfully return true,
	 * AT command result will send by broadcast with action android.intent.action.AtCommand.result
	 */
	boolean AtCommandSendUnSync(String cmd);
	
	/** 
	 * Execute AT command via sync tunnel
	 * @param cmd AT command, time is timeout of process unit is ms 
	 */
	String AtCommandSendSync(String cmd, int time); 

frameworks\base\telephony\java\com\android\internal\telephony\RILConstants.java

在尾部增加

int RIL_REQUEST_SEND_AT = 114;
...
int RIL_UNSOL_RESPONSE_TUNNEL_AT = 1038;

注意,兩個id必須在已有的基礎上按順序遞增添加。


frameworks\opt\telephony\src\java\com\android\internal\telephony\Phone.java

在尾部增加

	//Add AT tunnel
    void sendAtToModem(String at_string, Message result);

frameworks\opt\telephony\src\java\com\android\internal\telephony\PhoneBase.java

增加一個成員變量,表示主動上發的消息

protected static final int EVENT_UNSOL_AT_TUNNEL                = 31;


在尾部增加

@Override
    public void sendAtToModem(String at_string, Message result){
        Log.e(LOG_TAG, "sendAtToModem Error! This function is only for GSMPhone.");
    }

frameworks\opt\telephony\src\java\com\android\internal\telephony\PhoneProxy.java

在尾部增加

	@Override
    public void sendAtToModem(String at_string, Message result) {
        mActivePhone.sendAtToModem(at_string, result);
    }


如果是2G網絡,修改frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GSMPhone.java

如果是3G網絡,比如CDMA2000,修改frameworks\opt\telephony\src\java\com\android\internal\telephony\cdma\CDMAPhone.java

在構造函數增加

mCi.registerForAtTunnel(this, EVENT_UNSOL_AT_TUNNEL, null);

在dispose函數中添加

mCi.unregisterForAtTunnel(this);

在handleMessage中添加

			case EVENT_UNSOL_AT_TUNNEL:
                 ar = (AsyncResult)msg.obj;
                 log("receive EVENT_UNSOL_AT_TUNNEL done");
                 if (ar.exception == null) {
                     String result = (String)ar.result;
                     log("result = " + result);
                     sendResultBroadcast(result);
                 }
                 break;

在尾部添加

	private void sendResultBroadcast(String result) {
        Intent intent = new Intent("android.intent.action.AtCommand.result");
        intent.putExtra("result", result);
        mContext.sendBroadcast(intent);
    }
	
	@Override
    public void sendAtToModem(String at_string, Message result) {
        mCi.sendAtToModem(at_string, result);
    }


frameworks\opt\telephony\src\java\com\android\internal\telephony\CommandsInterface.java

在尾部添加

	//Add for AT tunnel to modem
    void sendAtToModem(String at_string, Message result);
    void registerForAtTunnel(Handler h, int what, Object obj);
    void unregisterForAtTunnel(Handler h);


frameworks\opt\telephony\src\java\com\android\internal\telephony\sip\SipCommandInterface.java

在尾部添加

	@Override
    public void sendAtToModem(String at_string, Message result){

    }


frameworks\opt\telephony\src\java\com\android\internal\telephony\test\SimulatedCommands.java

在尾部添加

	@Override
    public void sendAtToModem(String at_string, Message result){

    }

frameworks\opt\telephony\src\java\com\android\internal\telephony\BaseCommands.java

import android.os.Message;

添加一個成員變量,用於註冊處理主動上發的消息

protected Registrant mAtTunnelRegistrant;

在尾部添加

	/** 
     * Sets the handler for AT sync tunnel 
     * 
     * @param h Handler for notification message. 
     * @param what User-defined message code. 
     * @param obj User object. 
     */  
    @Override  
    public void registerForAtTunnel(Handler h, int what, Object obj) {  
        mAtTunnelRegistrant = new Registrant(h, what, obj);  
    }  
  
    @Override  
    public void unregisterForAtTunnel(Handler h) {  
        mAtTunnelRegistrant.clear();  
   }  
  
    @Override  
    public void sendAtToModem(String at_string, Message result) {  
   } 

frameworks\opt\telephony\src\java\com\android\internal\telephony\RIL.java

在processSolicited中添加

case RIL_REQUEST_SEND_AT: ret =  responseString(p); break;

在processUnsolicited中添加

case RIL_UNSOL_RESPONSE_TUNNEL_AT: ret =  responseString(p); break;
case RIL_UNSOL_RESPONSE_TUNNEL_AT: {
                if (RILJ_LOGD) unsljLogRet(response, ret);

                if (mAtTunnelRegistrant != null) {
                    mAtTunnelRegistrant.notifyRegistrant(
                                        new AsyncResult (null, ret, null));
                }
                break;
            }

在requestToString中添加

case RIL_REQUEST_SEND_AT: return "SEND_AT";

在responseToString中添加

case RIL_UNSOL_RESPONSE_TUNNEL_AT: return "RESPONSE_TUNNEL_AT";

在尾部添加

	@Override  
    public void sendAtToModem(String at_string, Message result) {  
		RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_AT, result);
		
        rr.mParcel.writeString(at_string);
		
        if (RILJ_LOGD) riljLog(rr.serialString() +
                              "> sendAtToModem: " + requestToString(rr.mRequest)
                              + " at_string: " + at_string);
							  
        send(rr);
   } 


packages\services\Telephony\src\com\android\phone\PhoneInterfaceManager.java

在尾部添加

	/**
     * Send AT command via unsync tunnel, it should return true or false when AT command has been send.
     * @param cmd AT command
     * return boolean
     */
    public boolean AtCommandSendUnSync(String cmd){
        Log.d(LOG_TAG, "AtCommandSendUnSync send at command" + cmd);
        Phone phone = mPhone;
        if (phone == null) return false;

        final AtSendThread atSendThread = new AtSendThread("AtCommandSendUnSync", cmd, false);
        atSendThread.start();
        String result =  atSendThread.sendAt(phone);
        sendResultBroadcast(result);
        if (result != null && result.length() > 1 && result.contains("OK")) {
            return true;
        } else {
            return false;
        }
    }
	
	private void sendResultBroadcast(String result) {
        Intent intent = new Intent("android.intent.action.AtCommand.result");
        intent.putExtra("result", result);
        mApp.getPhone().getContext().sendBroadcast(intent);
    }
	
	/**
    * Send AT command via sync tunnel, it should return result until the command execute completely.
    * @param cmd  AT command
    * @param time max time for executing at command, unit is ms.
    * return is result of AT.
    */
    public String AtCommandSendSync(String cmd, int time){
        Log.d(LOG_TAG, "AtCommandSendSync send at command" + cmd + " time = " + time);
        Phone phone = mPhone;
        if (phone == null) return null;

        final AtSendThread atSendThread = new AtSendThread("AtCommandSendSync", cmd, true, time);
        atSendThread.start();
        return atSendThread.sendAt(phone);
    }
	
	private static class AtSendThread extends Thread {
        private String mCmd;
        private long mMaxTimeExcute;
        private String mAtResult;
        private boolean mIsSync;
        private Handler mAtHandler;
        private boolean mSuccess = false;

        private static final int SEND_AT_VIA_TUNNEL = 1;

        AtSendThread(String name, String cmd, boolean isSync) {
             super(name);
             mCmd = cmd;
             mAtResult = null;
             mMaxTimeExcute = 5;
             mIsSync = false;
        }

        AtSendThread(String name, String cmd, boolean isSync, int max) {
            super(name);
            mCmd = cmd;
            mMaxTimeExcute = (long)(max/100);
            mAtResult = null;
            mIsSync = isSync;
       }

        public void run() {
            Looper.prepare();
            synchronized (AtSendThread.this) {
                mAtHandler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        AsyncResult ar = (AsyncResult) msg.obj;
                        switch (msg.what) {
                            case SEND_AT_VIA_TUNNEL:
                                Log.d("AtSyncThread", "SEND_AT_VIA_TUNNEL");
                                synchronized (AtSendThread.this) {
                                    if (ar.exception == null && ar.result != null) {
                                        mAtResult = ar.result.toString();
                                    }else{
										mAtResult = "Error AT response";
									}
                                    mSuccess = true;
                                    AtSendThread.this.notifyAll();
                                }
                                break;
                        }
                    }
                };
                AtSendThread.this.notifyAll();
            }
            Looper.loop();
        }

        synchronized String sendAt(Phone phone) {
            while (mAtHandler == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            Message callback = Message.obtain(mAtHandler, SEND_AT_VIA_TUNNEL);
            Log.e(LOG_TAG, "mCmd = " + mCmd);
            phone.sendAtToModem(mCmd, callback);
            while (!mSuccess) {
                try {
                    Log.d("AtSendThread", "wait for done");
                    mMaxTimeExcute--;
                    wait(100);
                    if (mMaxTimeExcute == 0) {
                        mAtResult = "Error AT TIME OUT";
                        return mAtResult;
                    }
                } catch (InterruptedException e) {
                    // Restore the interrupted status
                    Thread.currentThread().interrupt();
                }
            }
            Log.d("AtSendThread", "successfull! result = " + mAtResult);
            return mAtResult;
        }
    }


hardware\ril\include\telephony\ril.hhardware\ril\reference-ril\ril.h
添加兩條命令碼

#define RIL_REQUEST_SEND_AT 114
...
#define RIL_UNSOL_RESPONSE_TUNNEL_AT 1038

注意要與上面的RILConstants.java添加的相同

hardware\ril\libril\ril_commands.h

在尾部添加

{RIL_REQUEST_SEND_AT, dispatchString, responseString},

hardware\ril\libril\ril_unsol_commands.h

在尾部添加

{RIL_UNSOL_RESPONSE_TUNNEL_AT, responseString, WAKE_PARTIAL},

hardware\ril\reference-ril\reference-ril.c

在onRequest中添加處理RILJ發送過來的AT命令

case RIL_REQUEST_SEND_AT:
			requestSendAt(data, datalen, t);
			break;

static void requestSendAt(void *data, size_t datalen, RIL_Token t)
{
    int err;
    char *cmd;
    char *response;
    ATResponse *p_response = NULL;

    RLOGD("requestSendAt data = %s, datalen = %d", (char *)data, datalen);
    assert (datalen != 1);

	
    asprintf(&cmd, "%s", (char *)data+1);
	response = (char *)data;
	if(response[0] == '1'){
		err = at_send_command(cmd, &p_response);
	}else if(response[0] == '2'){
		err = at_send_command_singleline(cmd, "", &p_response);
	}else if(response[0] == '3'){
		err = at_send_command_numeric(cmd, &p_response);
	}else if(response[0] == '4'){
		err = at_send_command_multiline(cmd, "", &p_response);
	}else{
		err = -1;
	}
	
    if (cmd != NULL) {
        free(cmd);
        cmd = NULL;
    }

    RLOGD("requestSendAt err = %d, p_response->success = %d", err, p_response->success);
    if (p_response->p_intermediates == NULL) {
        RLOGD("requestSendAt finalResponse = %s", p_response->finalResponse);
        asprintf(&response, "%s\r\n", p_response->finalResponse);
    } else {
        RLOGD("requestSendAt finalResponse = %s, p_intermediates->line = %s", p_response->finalResponse, p_response->p_intermediates->line);
        asprintf(&response, "%s, %s\r\n", p_response->p_intermediates->line, p_response->finalResponse);
    }
    if (err < 0 || p_response->success == 0)
        /*Maybe the at command from user is invalid, we also send successful response to user, the result should handle it itself*/
        goto error;

    RLOGD("requestSendAt success, response = %s, len = ", response, strlen(response));
    RIL_onRequestComplete(t, RIL_E_SUCCESS, response, strlen(response));
    free(response);
    return;

error:
    RLOGE("ERROR: requestSendAt failed, response = %d", response);
    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
    free(response);
}

注意,你需要知道下發的命令要不要求返回數據,如果不要求一般用at_send_command即可,要求就用at_send_command_singleline。這個不能出錯,否則RILJ和RILC之間的socket會斷開。

在onUnsolicited中添加主動上發消息的處理

else{
  if(!s) {
   line = strdup(s);
   memset(atReadStorage, 0, 1024);
   
   strncpy(atReadStorage, line, strlen(line));
   p = atReadStorage + strlen(line);
   
   if(!sms_pdu) {
    strncpy(p, sms_pdu, strlen(sms_pdu));
   }
   
   RIL_onUnsolicitedResponse (
    RIL_UNSOL_RESPONSE_TUNNEL_AT,
    atReadStorage, strlen(atReadStorage));
   free(line);
  }
    }

注意,這個要放在已有的if-else語句的最後,目的是把過濾剩下的消息全部當成RIL_UNSOL_RESPONSE_TUNNEL_AT上發,其中atReadStorage爲靜態內存塊。

static char atReadStorage[1024];


調試的時候可以用logcat -b radio命令查看信息。

一些常見的LOG TAG是:

 RIL: /hardware/ril/reference-ril/refereince-ril.c
 AT: /hardware/ril/reference-ril/atchannel.c
 RILD: /hardware/ril/rild/rild.c
 RILC: /hardware/ril/libril/ril.cpp
 RILB frameworks/base/telephony/java/com/android/internal/telephony/BaseCommands.java
 RILJ: /frameworks/base/telephony/java/com/android/internal/telephony/gsm/RIL.java
 GSM: /frameworks/base/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章