一些有关系统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;
}

浙公网安备 33010602011771号