一些有关系统APK的探索(二)

之前说了系统签名,这篇说下系统应用phone,因为是老版本的知识就不写太多了,简约说下吧

这是网上找的图和说明

  Phone服务:是指Phone所能提供的各种服务(来电去电,短信,SIM的锁定,数据连结传输等)与service不是同一个概念。

           Phone 中的service是ITelephony和ITelephonyRegistry的实现类,PhoneInterfaceManager.java和TelephonyRegistry.java,后续说明。

      GSMPhone: 管理了电话服务的内部功能,也对RIL层进行了封装,上层应用不能直接跟RIL本地代码打交道,而是间接通过GSMPhone.但是应用层为了更方便的访问电话服

        务,需要在GSMPhone之上的TelephonyManager。

      TelephonyManager:通过两个IBinder接口ITelephony和ITelephonyRegistry来完成这项工作。

          ITelephony是电话服务用户(用户层或框架其他部分)主动进行RIL访问的路径,它的服务端实现类不在代码中,而是在Phone应用

               PhoneInterfaceManager.java(packages/apps/Phone/src/com/android/phone/)中。PhoneInterfaceManager.publish中以”phone”为名注册该服务,

                  提供拨号界面、呼叫、挂机等呼叫相关控制,也提供SIM PIN、开关Radio等操作,他的实现是通过调用Phone接口来操作。

              ItelephonyRegistry提供一个通知机制,将底层状态变更通知给电话服务的用户(用户层或框架其他部分),是用户被动通知的路径,通知消息如网络状态、信

                 号强弱更新、电话状态更新等。它的服务端实现在框架代码中TelephonyRegistry.java(frameworks/base/services/java/com/android/server/)。底层

                 通知的来源,是GSMPhone通过PhoneNotifier的实现者DefaultPhoneNotifier将具体的事件转化为函数调用并且通知到TelephonyRegistry。

 TelephonyRegistry再通过两种方式通知给用户,其一是广播事件,另外一种是通过服务用户在TelephonyRegistry中注册的IphoneStateListener接口,实现回调。

播打电话流程:

  首先:

    mPhone = PhoneApp.getInstance().phone;

    Intent intent = getIntent();
    if (LOGV) Log.v(TAG, "onResume: Got intent " + intent + ".");

    String action = intent.getAction();
    String number = PhoneNumberUtils.getNumberFromIntent(intent, this);

    //获取到PhoneApp对象,获取Intent,并且取得拨出的号码,然后,对号码进行处理之后判断是不是紧急号码,如120。。。

    //如果是紧急号码,直接startActivity启动InCallScreen,同时将callNow变量赋值为true

    //于是InCallScrenn启动唤醒屏幕。。。

    //而在receiver里面判断callNow为ture就直接finish,而不再重复启动InCallScreen

    //如果不是紧急号码就发送广播“Intent.ACTION_NEW_OUTGOING_CALL”,让别人进行处理

    broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
    broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, intent.getData().toString());
    if (LOGV) Log.v(TAG, "Broadcasting intent " + broadcastIntent + ".");
    sendOrderedBroadcast(broadcastIntent, PERMISSION, null, null,Activity.RESULT_OK, number, null);

  然后:

    接收到广播(OutgoingCallBroadcaster)之后,从Intent里面取出电话号码及其URi originalUri = intent.getStringExtra(OutgoingCallBroadcaster.EXTRA_ORIGINAL_URI);

    然后,设置Intent为ACTION_CALL,并带上号码和url并从Intent中取出callnow变量,如果为ture,表示在OutgoingCallBroadcaster中已经把InCallScrenn启动,所以不需要

    重复启动,而是直接把自己给finish如果为false,表示不是紧急号码,并且InCallScrenn没有被启动,所以需要将InCallScrenn启动,如下:

     Intent newIntent = new Intent(Intent.ACTION_CALL, uri);
    newIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
    newIntent.setClass(context, InCallScreen.class);
    newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    context.startActivity(newIntent);

    并且启动对应的Activity

接听电话的流程:

  创建CDMAPhone时,mCT = new CdmaCallTracker(this);

  创建CDMACallTracker时,cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);-->BaseCommands.mCallStateRegistrants.add(r);

  RIL中的RILReceiver线程首先读取从rild中传来的数据:RIL.processResponse->RIL.processSolicited

  对应于incoming call,RIL.java收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息,触发mCallStateRegistrants中的所有记录。

  CdmaCallTracker处理EVENT_CALL_STATE_CHANGE,调用pollCallsWhenSafe

  函数pollCallsWhenSafe处理:

  lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);

  cm.getCurrentCalls(lastRelevantPoll);

  RIL.getCurrentCalls

  RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);

  send(rr);

  接着RIL调用processSolicited处理RIL_REQUEST_GET_CURRENT_CALLS的返回结果。

  CdmaCallTracker的handleMessage被触发,处理时间EVENT_POLL_CALLS_RESULT,调用函数handlePollCalls

  CdmaCallTracker.handlePollCalls调用phone.notifyNewRingingConnection(newRinging);

  PhoneApp中创建CallNotifier

  mPhone.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);

  CallNotifier.java,onNewRingingConnection()->startIncomingCallQuery()->startGetCallerInfo()

  CallNofifier.java,onPhoneStateChanged()

  InCallScreen.java,onPhoneStateChanged()

  CallNotifier.java,onQueryComplete()->onCustomRingQueryComplete()(mRinger.ring()响铃,PhoneUtils.showIncomingCallUi()更新UI)

  如果接通电话,则调用InCallScreen.java,handleOnscreenButtonClick()->internalAnswerCall()->PhoneUtils.answerCall(mPhone);(停止响铃,然后再接听电话)

  CallNotifier.java,operationComplete()

  状态改变InCallScreen.java,onPhoneStateChanged()更新界面,完成接听电话功能。

挂断电话的流程:  

  拖动挂断界面InCallTouchUi.java,onTrigger()

  InCallScreen.java,internalHangupRingingCall()->PhoneUtils.hangupRingingCall()->PhoneUtils.hangup()->CdmaCall.hangup()

  CdmaCallTracker.java,hangup()(先只看第一种情况)->cm.hangupWaitingOrBackground

  RIL.java,hangupWaitingOrBackground()

  注1:dialButtonPressed()函数,会启动一个intent.该intent的ACTION是ACTION_CALL_PRIVILEGED。我们在Intent.java中可以看到ACTION_CALL_PRIVILEGED实际上就是

      CALL_PRIVILEGED。在phone包下,查看AndroidManifest.xml可以看到<activity-alias />标签。这个标签的意思是说,这个Activity是另一个Activity的别名,真实的Activity

      在标签中用“android:targetActivity = OutgoingCallBroadcast”标出,所以 “ACTION_CALL_PRIVILEGED”启动的PrivilegedOutgoingCallBroadcast 所对应的真实“身份”是

      “OutgoingCallBroadcast”。

  注2:InCallScreen.java在首次oncreate后,就算通话结束也只会调用其onstop方法,此类一直不会被finish()掉。当onstop后,若重新打电话,则会调用onnewintent()方法,不会

    再经过oncreate。onCreate(第一次)增加FLAG参数:FLAG_DISMISS_KEYGUARD(这个参数的作用主要在于解除锁屏,比如锁屏时来电,这时候就需要先解除锁屏再显示

    画面,这样用户就能在锁屏时接收到来电了)

    InCallScreen布局及各个功能该类extends了Acitivity,并且implements了OnClickListener和OnTouchListener,

    所以该类主要是负责打电话的那一个界面,并且还负责各种按键事件和触摸时间的处理。同时本类还复写的finish()方法,所以一般不会被finish掉,调用这个方法时它又把自

    己放回栈中。

    InCallScreen可以接收这个Intent并启动。在onCreate里面将各个view加载。在onResume里面进行一些初始化操作,如:获取一个PhoneApp对象 解开Keyguard

    Notification的statusBar给DIsable。。。。还内置了一个Handler可以回调处理一些事件,比如: PHONE_STATE_CHANGED ;PHONE_DISCONNECT ;  

    EVENT_HEADSET_PLUG_STATE_CHANGED 同时有一个独立的BroadcastReceiver处理ACTION_HEADSET_PLUG,比如插入耳机等。。。。

  (1)包含CallCard类:CallCard负责通话主要界面(callcard里面又包含call_card_person_info,这个就不细说了),如显示保持恢复按钮,电话头像,通话时间,通话号码或人

      名以及通话人头像。

    (2)包含dtmf_twelve_key_dialer配置文件:主要负责通话中拨号键盘的布局

  (3)包含InCallTouchUi这个重要的类:主要负责来电时的锁屏界面(往左滑是拒绝来电,往右滑是接听来电),该类继承SlidingTab来实现滑屏效果,后面会说到运用

      SlidingTab能实现自己的来电锁屏界面

    (4)包含incallmenu类,主要负责MENU菜单的一些操作(如挂断电话,免提,合并通话等),虽然incallmenu负责MENU的绘画及布局,但是实际onclick后的操作是由

    incallscreen类来操控的

PhoneApp

  该类是一个普通的java类,主要负责Phone对象的生成,这是一个虚拟的Phone对象,它从framework层取得一个Phone对象。该类继承自Application,同时能常驻内存

  他和PhoneUtils一起处理电话操作,在oncreate方法里面进行各种全局的初始化:获取Phone对象 NotificationMgr对象 PowerManager对象 SimCard对象等。。。

  同时内置的Handler可以回调处理各种事件,如:EVENT_SIM_ABSENT EVENT_SIM_NETWORK_LOCKED EVENT_UPDATE_INCALL_NOTIFICATION等。。。

备注:

  Phone源代码中锁屏相关类: PhoneApp.java中的updateWakeState()方法

    Phone中查询联系人信息相关: 在PhoneUtils类startGetCallerInfo方法里

  往外跳转的类:

    在PhoneApp类里有

    //控制在结束时跳转到通讯录

    static Intent createCallLogIntent() {

      //Intent.ACTION_VIEW会跳转到action为android.intent.action.VIEW的类里(系统Contacts)

      Intent intent = new Intent(Intent.ACTION_VIEW, null);

      //定位到系统Contacts的DialtactsActivity类里

      intent.setType("vnd.android.cursor.dir/calls");

      return intent;

    }

    在OutgoingCallBroadcaster类里有

    //有需要紧急电话但是打不通时会调用(?)

    Intent invokeFrameworkDialer = new Intent();

    // TwelveKeyDialer is in a tab so we really want

    // DialtactsActivity. Build the intent 'manually' to

    // use the java resolver to find the dialer class (as

    // opposed to a Context which look up known android

    // packages only)

    invokeFrameworkDialer.setClassName("com.android.contacts","com.android.contacts.DialtactsActivity");

    invokeFrameworkDialer.setAction(Intent.ACTION_DIAL);

    invokeFrameworkDialer.setData(intent.getData());

    在DataUsage类里有

    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {

    if (preference == mHelpPref) {

      try {

      //Intent.ACTION_VIEW会跳转到action为android.intent.action.VIEW的类里(系统Contacts)

        Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(mHelpUri));

        startActivity(myIntent);

      } catch (Exception e) {

      }

    }

    return true;
    }

 

posted @ 2019-07-28 23:14  释绝  阅读(163)  评论(0)    收藏  举报