phone服务相关

景河
2023-12-01

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


 类似资料: