phone服务相关

来源:互联网 发布:spss mac版怎么保存 编辑:程序博客网 时间:2024/05/19 17:27

phone系统服务概述

Android系统中framework和app用到名称为phone的服务还是比较多的,需要用到的是ITelephony.aidl

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

    void answerRingingCall();
ITelephony中有各种通讯相关接口,从设计角度来说这个服务中的很多方法是不供三方app调用的,但还是有方法(例如反射)可以使用ITelphony的。不然各种系统管家和骚扰拦截程序怎么能挂断电话呢

服务发布

服务实现是在PhoneInterfaceManager.java中,位于Telephony包下,该包编译后是TeleService.apk,进程就是包名com.android.phone

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

public class PhoneInterfaceManager extends ITelephony.Stub {

    /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {        synchronized (PhoneInterfaceManager.class) {            if (sInstance == null) {                sInstance = new PhoneInterfaceManager(app, phone);            } else {                Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);            }            return sInstance;        }    }
单例模式

    private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {        ...        publish();    }
    private void publish() {        if (DBG) log("publish: " + this);        ServiceManager.addService("phone", this);    }
构造函数中调用publish(), 然后添加名称为phone的服务到系统中。init的调用链如下:

packages/services/Telephony/src/com/android/phone/PhoneApp.java

public class PhoneApp extends Application {
该类继承自Application类,即phone进程一启动必会走onCreate方法
 @Override    public void onCreate() {        if (UserHandle.myUserId() == 0) {            // We are running as the primary user, so should bring up the            // global phone state.            mPhoneGlobals = new PhoneGlobals(this);            mPhoneGlobals.onCreate();            ...        }    }
packages/services/Telephony/src/com/android/phone/PhoneGlobals.java

    public void onCreate() {            ...            phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());            ...    }
phone进程一启动phone服务就添加到系统中,其它进程就可以通过ITelephony调用phone服务

服务实现

拿一个函数举例,就是概述中的answerRingingCall

    public void answerRingingCall() {        answerRingingCallForSubscriber(getDefaultSubscription());    }
   public void answerRingingCallForSubscriber(int subId) {        if (DBG) log("answerRingingCall...");        // TODO: there should eventually be a separate "ANSWER_PHONE" permission,        // but that can probably wait till the big TelephonyManager API overhaul.        // For now, protect this call with the MODIFY_PHONE_STATE permission.        enforceModifyPermission();        sendRequest(CMD_ANSWER_RINGING_CALL, null, new Integer(subId));    }

   /**     * Posts the specified command to be executed on the main thread,     * waits for the request to complete, and returns the result.     * @see #sendRequestAsync     */    private Object sendRequest(int command, Object argument, Integer subId) {        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {            throw new RuntimeException("This method will deadlock if called from the main thread.");        }        MainThreadRequest request = new MainThreadRequest(argument, subId);        Message msg = mMainThreadHandler.obtainMessage(command, request);        msg.sendToTarget();        // Wait for the request to complete        synchronized (request) {            while (request.result == null) {                try {                    request.wait();                } catch (InterruptedException e) {                    // Do nothing, go back and wait until the request is complete                }            }        }        return request.result;    }
发送CMD_ANSWER_RINGING_CALL请求到mMainThreadHandler处理,如字面意思该Handler的作用就是把代码运行在主线程,然后binder线程同步wait到结果返回给调用端。Looper.myLooper() 获得的Looper实际就是binder thread的Looper,所以它们一般情况下肯定是不相等的,除非是phone进程代码直接调用该类方法(这个就和binder没有任何关系了,相当于调用一个类的成员方法,但是phone进程这样做其实没有任何意义,因为这个本来就是对外提供服务,phone进程本身要实现同样功能很简单)。

                case CMD_ANSWER_RINGING_CALL:                    request = (MainThreadRequest) msg.obj;                    int answer_subId = request.subId;                    answerRingingCallInternal(answer_subId);                    // Wake up the requesting thread                    /// M: for ALPS02014935. 2015-04-02 @{                    synchronized (request) {                        request.result = "OK";                        request.notifyAll();                    }                    /// @}                    break;
mMainThreadHandler消息处理中调用answerRingingCallInternal方法

    private void answerRingingCallInternal(int subId) {        final boolean hasRingingCall = !getPhone(subId).getRingingCall().isIdle();        if (hasRingingCall) {            final boolean hasActiveCall = !getPhone(subId).getForegroundCall().isIdle();            final boolean hasHoldingCall = !getPhone(subId).getBackgroundCall().isIdle();            if (hasActiveCall && hasHoldingCall) {                // Both lines are in use!                // TODO: provide a flag to let the caller specify what                // policy to use if both lines are in use.  (The current                // behavior is hardwired to "answer incoming, end ongoing",                // which is how the CALL button is specced to behave.)                PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());                return;            } else {                // answerCall() will automatically hold the current active                // call, if there is one.                PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());                return;            }        } else {            // No call was ringing.            return;        }    }
answerRingingCallInternal调用PhoneUtils中相关方法,例如answerCall方法,其实通话UI中接听电话调用的也是该方法,可见phone服务就是开放部分功能对外使用。

使用举例

frameworks/base/telephony/java/android/telephony/TelephonyManager.java

大多三方app不必直接使用ITelephony.aidl,用TelephonyManager即可,这个是sdk中设计的通讯相关类。

  private ITelephony getITelephony() {        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));    }
getITelephony方法获取的就是phone服务

    public String getDeviceId() {        try {            ITelephony telephony = getITelephony();            if (telephony == null)                return null;            return telephony.getDeviceId(mContext.getOpPackageName());        } catch (RemoteException ex) {            return null;        } catch (NullPointerException ex) {            return null;        }    }
拿getDeviceId举例,就是使用phone服务获取设备imei或者meid


0 0
原创粉丝点击