1. Telecom所处位置

由下图,Telecom的作用是起到交互桥梁,与IncallUI 和 Telephony【Phone进程、TeleService】交互

路径 统称 进程
packages/app/Dialer Dialer com.android.dialer
packages/service/telecomm telecom system_service
packages/service/telephony TeleService com.android.phone
framework/base/telecomm framework 无进程只是提供调用framwork
framework/opt/Telephony telephony system_service或com.android.phone

2. 什么是Telecom 服务

telecom所处的代码路径:

代码路径:

  • /packages/services/Telecomm
  • /frameworks/base/telecomm/java/android/telecom/

Telecom是Android的一个系统服务,其主要作用是管理Android系统当前的通话,如来电显示,接听电话,挂断电话等功能,在Telephony模块与上层UI之间起到了一个桥梁的作用。比如,Telephony有接收到新的来电时,首先会告知Telecom,然后由Telecom服务通知上层应用来电信息,并显示来电界面。

Telecom服务对外提供了一个接口类TelecomManager,通过其提供的接口,客户端可以查询通话状态,发送通话请求以及添加通话链接等。

Telecom进程对应的AndroidManifest.xml文件来看,Telecom进程的用户ID跟系统进程用户ID相同,是系统的核心服务。那么,其中android:process="system"这个属性值表示什么意思了?查看官方文档,这个表示Telecom将启动在进程system中,这样可以跟其他进程进行资源共享了(对于Android这个全局进程,就是SystemServer所在的进程)。

AndroidManifest.xml 在/packages/services/Telecomm,包含了 ITelecomService

/packages/services/Telecomm/AndroidManifest.xml

17 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
18         xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
19         package="com.android.server.telecom"
20         coreApp="true"
21         android:sharedUserId="android.uid.system">
22
23     <protected-broadcast android:name="android.intent.action.SHOW_MISSED_CALLS_NOTIFICATION" />
24     <protected-broadcast android:name="com.android.server.telecom.MESSAGE_SENT" />330         <service android:name=".components.BluetoothPhoneService"
331                 android:singleUser="true"
332                 android:process="system">
333             <intent-filter>
334                 <action android:name="android.bluetooth.IBluetoothHeadsetPhone" />
335             </intent-filter>
336         </service>
337
338         <service android:name=".components.TelecomService"
339                 android:singleUser="true"
340                 android:process="system">
341             <intent-filter>
342                 <action android:name="android.telecom.ITelecomService" />
343             </intent-filter>
344         </service>
345
346     </application>
347 </manifest>

3. Telecom代码路径

1) /packages/services/Telecomm 代码路径

action: android.intent.action.CALL

141         <!-- Activity that starts the outgoing call process by listening to CALL intent which
142              contain contact information in the intent's data. CallActivity handles any data
143              URL with the schemes "tel", "sip", and "voicemail". It also handles URLs linked to
144              contacts provider entries. Any data not fitting the schema described is ignored. -->
145         <activity android:name=".components.UserCallActivity"
146                 android:label="@string/userCallActivityLabel"
147                 android:theme="@style/Theme.Telecomm.Transparent"
148                 android:permission="android.permission.CALL_PHONE"
149                 android:excludeFromRecents="true"
150                 android:process=":ui">
151             <!-- CALL action intent filters for the various ways of initiating an outgoing call. -->
152             <intent-filter>
153                 <action android:name="android.intent.action.CALL" />
154                 <category android:name="android.intent.category.DEFAULT" />
155                 <data android:scheme="tel" />-------------
184         <activity-alias android:name="PrivilegedCallActivity"
185                 android:targetActivity=".components.UserCallActivity"
186                 android:permission="android.permission.CALL_PRIVILEGED"
187                 android:process=":ui">
188             <intent-filter android:priority="1000">
189                 <action android:name="android.intent.action.CALL_PRIVILEGED" />
190                 <category android:name="android.intent.category.DEFAULT" />
191                 <data android:scheme="tel" />
192             </intent-filter>

action:android.intent.action.CALL_EMERGENCY

212         <!-- Works like CallActivity with CALL_EMERGENCY instead of CALL intent.
213              CALL_EMERGENCY allows calls *only* to emergency numbers. Intent-sender must have the
214              CALL_PRIVILEGED permission or the broadcast will not be processed. High priority of
215              1000 is used in all intent filters to prevent anything but the system from processing
216              this intent (b/8871505). -->
217         <!-- TODO: Is there really a notion of an emergency SIP number? If not, can
218              that scheme be removed from this activity? -->
219         <activity-alias android:name="EmergencyCallActivity"
220                 android:targetActivity=".components.UserCallActivity"
221                 android:permission="android.permission.CALL_PRIVILEGED"
222                 android:process=":ui">
223             <intent-filter android:priority="1000">
224                 <action android:name="android.intent.action.CALL_EMERGENCY" />
225                 <category android:name="android.intent.category.DEFAULT" />
226                 <data android:scheme="tel" />
227             </intent-filter>

2) /frameworks/base/telecomm/java/android/telecom/ 框架层路径

4. Telecom进程的启动和初始化

  • /frameworks/base/services/java/com/android/server/SystemServer.java

首先会走到 main 方法中,然后在调用 run 方法:在SystemServer进程初始化完成启动完系统的核心服务如ActivityManagerService后,就会加载系统其它服务,这其中就包含了一个与Telecom服务启动相关的系统服务专门用于加载Telecom

917      private void startOtherServices() {
1004                  traceBeginAndSlog("StartTelecomLoaderService");
1005                  mSystemServiceManager.startService(TelecomLoaderService.class);
1006                  traceEnd();
1007
1008                  traceBeginAndSlog("StartTelephonyRegistry");
1009                  telephonyRegistry = new TelephonyRegistry(context);
1010                  ServiceManager.addService("telephony.registry", telephonyRegistry);
1011                  traceEnd();
  • /frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

调用系统服务管家SystemServiceManager的接口startService创建新的服务,并注册到系统中,最后调用onStart()启动服务。

public class SystemServiceManager {@SuppressWarnings("unchecked")public SystemService startService(String className) {final Class<SystemService> serviceClass;try {serviceClass = (Class<SystemService>)Class.forName(className);} catch (ClassNotFoundException ex) {....}return startService(serviceClass);}// 服务的class文件来创建新的服务对象(服务必须继承SystemService)@SuppressWarnings("unchecked")public <T extends SystemService> T startService(Class<T> serviceClass) {try {final String name = serviceClass.getName();Slog.i(TAG, "Starting " + name);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);// Create the service.if (!SystemService.class.isAssignableFrom(serviceClass)) {throw new RuntimeException("Failed to create " + name+ ": service must extend " + SystemService.class.getName());}final T service;try {Constructor<T> constructor = serviceClass.getConstructor(Context.class);service = constructor.newInstance(mContext);} catch (InstantiationException ex) {throw new RuntimeException("Failed to create service " + name+ ": service could not be instantiated", ex);} ....// Register it.mServices.add(service);// Start it.try {service.onStart();} catch (RuntimeException ex) {throw new RuntimeException("Failed to start service " + name+ ": onStart threw an exception", ex);}return service;} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}}}
  • /frameworks/base/services/core/java/com/android/server/telecom/TelecomLoaderService.java

创建TelecomLoaderService系统服务,将系统默认的SMS应用,拨号应用以及SIM通话管理应用告知PackageManagerService(PMS),以便在适当的时候可以找到应用。

public class TelecomLoaderService extends SystemService {...public TelecomLoaderService(Context context) {super(context);mContext = context;registerDefaultAppProviders();}@Overridepublic void onStart() {}private void registerDefaultAppProviders() {final PackageManagerInternal packageManagerInternal = LocalServices.getService(PackageManagerInternal.class);// Set a callback for the package manager to query the default sms app.packageManagerInternal.setSmsAppPackagesProvider(new PackageManagerInternal.PackagesProvider() {@Overridepublic String[] getPackages(int userId) {synchronized (mLock) {....ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(mContext, true);if (smsComponent != null) {return new String[]{smsComponent.getPackageName()};}return null;}});// Set a callback for the package manager to query the default dialer app.packageManagerInternal.setDialerAppPackagesProvider(new PackageManagerInternal.PackagesProvider() {@Overridepublic String[] getPackages(int userId) {synchronized (mLock) {....String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext);if (packageName != null) {return new String[]{packageName};}return null;}});// Set a callback for the package manager to query the default sim call manager.packageManagerInternal.setSimCallManagerPackagesProvider(new PackageManagerInternal.PackagesProvider() {@Overridepublic String[] getPackages(int userId) {synchronized (mLock) {....TelecomManager telecomManager =(TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);if (phoneAccount != null) {return new String[]{phoneAccount.getComponentName().getPackageName()};}return null;}});}}

telecom 服务的启动:

有一个onBootPhase的函数,用于SystemServer告知系统服务目前系统启动所处的阶段。这里可以看到,等(ActivityManagerService)AMS启动完成以后,就可以开始连接Telecom服务了:

  • 首先,注册默认应用(SMS/Dialer etc)通知对象,以便这些应用发送变更(如下载了一个第三方的SMS应用时,可以通知系统这一变化);
  • 接着,注册运营商配置变化的广播接收器,如果配置有变化时,系统会收到通知;
  • 绑定TelecomService,并将其注册到系统中。
public class TelecomLoaderService extends SystemService {private static final ComponentName SERVICE_COMPONENT = new ComponentName("com.android.server.telecom","com.android.server.telecom.components.TelecomService");private static final String SERVICE_ACTION = "com.android.ITelecomService";// 当前系统启动的阶段@Overridepublic void onBootPhase(int phase) {if (phase == PHASE_ACTIVITY_MANAGER_READY) {registerDefaultAppNotifier();registerCarrierConfigChangedReceiver();connectToTelecom();}}//绑定Telecom服务private void connectToTelecom() {synchronized (mLock) {if (mServiceConnection != null) {// TODO: Is unbinding worth doing or wait for system to rebind?mContext.unbindService(mServiceConnection);mServiceConnection = null;}TelecomServiceConnection serviceConnection = new TelecomServiceConnection();Intent intent = new Intent(SERVICE_ACTION);intent.setComponent(SERVICE_COMPONENT);int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE| Context.BIND_AUTO_CREATE;// Bind to Telecom and register the serviceif (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.SYSTEM)) {mServiceConnection = serviceConnection;}}}}
  • /packages/services/Telecomm/src/com/android/server/telecom/components/TelecomService.java

绑定服务时,调用TelecomServiceonBind接口,对整个Telecom系统进行初始化,并返回一个IBinder接口:

/*** Implementation of the ITelecom interface.*/public class TelecomService extends Service implements TelecomSystem.Component {@Overridepublic IBinder onBind(Intent intent) {// 初始化整个Telecom系统initializeTelecomSystem(this);//返回IBinder接口synchronized (getTelecomSystem().getLock()) {return getTelecomSystem().getTelecomServiceImpl().getBinder();}}}

Telecom系统初始化,主要工作是新建一个TelecomSystem的类,在这个类中,会对整个Telecom服务的相关类都初始化

static void initializeTelecomSystem(Context context) {if (TelecomSystem.getInstance() == null) {final NotificationManager notificationManager =(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);// 用于获取联系人contactInfoHelper = new ContactInfoHelper(context);// 新建一个单例模式的对象TelecomSystem.setInstance(new TelecomSystem(....));}....}}
  • /packages/services/Telecomm/src/com/android/server/telecom/TelecomSystem.java

构造一个单例TelecomSystem对象,会创建许多和通话有关的类

public TelecomSystem(Context context,/* 用户未接来电通知类(不包括已接或者拒绝的电话) */MissedCallNotifierImplFactory missedCallNotifierImplFactory,/* 查询来电信息 */CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,/* 耳机接入状态监听 */HeadsetMediaButtonFactory headsetMediaButtonFactory,/* 距离传感器管理 */ProximitySensorManagerFactory proximitySensorManagerFactory,/* 通话时电话管理 */InCallWakeLockControllerFactory inCallWakeLockControllerFactory,/* 音频服务管理 */AudioServiceFactory audioServiceFactory,/* 蓝牙设备管理 */BluetoothPhoneServiceImplFactory bluetoothPhoneServiceImplFactory,BluetoothVoIPServiceImplFactory bluetoothVoIPServiceImplFactory,/* 查询所有超时信息 */Timeouts.Adapter timeoutsAdapter,/* 响铃播放 */AsyncRingtonePlayer asyncRingtonePlayer,/* 电话号码帮助类 */PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,/* 通话时阻断通知 */InterruptionFilterProxy interruptionFilterProxy) {mContext = context.getApplicationContext();// 初始化telecom相关的featureTelecomFeature.makeFeature(mContext);// 初始化telecom的数据库TelecomSystemDB.initialize(mContext);// 创建一个PhoneAccount注册管理类mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext);....// 初始化通话管家,正是它负责与上层UI的交互mCallsManager = new CallsManager(mContext, mLock, mContactsAsyncHelper,callerInfoAsyncQueryFactory, mMissedCallNotifier,mPhoneAccountRegistrar, headsetMediaButtonFactory,proximitySensorManagerFactory, inCallWakeLockControllerFactory,audioServiceFactory, bluetoothManager,wiredHeadsetManager, systemStateProvider,defaultDialerAdapter, timeoutsAdapter,AsyncRingtonePlayer,phoneNumberUtilsAdapter,  interruptionFilterProxy);CallsManager.initialize(mCallsManager);// 注册需要接收的广播    mContext.registerReceiver(mUserSwitchedReceiver, USER_SWITCHED_FILTER);mContext.registerReceiver(mUserStartingReceiver, USER_STARTING_FILTER);mContext.registerReceiver(mFeatureChangedReceiver, FEATURE_CHANGED_FILTER);mContext.registerReceiver(mEmergencyReceiver, EMERGENCY_STATE_CHANGED);....    // 所有来电与去电的处理中转站mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager);// 创建一个TelecomServiceImpl用于调用TelecomService的接口mTelecomServiceImpl = new TelecomServiceImpl(mContext, mCallsManager, mPhoneAccountRegistrar,new CallIntentProcessor.AdapterImpl(),new UserCallIntentProcessorFactory() {@Overridepublic UserCallIntentProcessor create(Context context, UserHandle userHandle) {return new UserCallIntentProcessor(context, userHandle);}},defaultDialerAdapter,new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),mLock);// 执行特定的初始化操作initialize(mContext);}}

5. 核心 Listener 的回调机制【核心类:CallsManager】

在解析拨号流程和来电流程的过程中,遇见了各式各样的Listener 消息回调。本节将重点解析 Telecom 中的 Listener 消息处理机制

/packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java

1) CallsManagerListener 接口:

在TelecomSystem 初始化过程中创建CallsManager 对象时,将同步创建C llsManagerlistener 对象,并注册Listener 消息通知,查看CallsManager 类的构造方法

监听通话的一系列状态

    public interface CallsManagerListener {void onCallAdded(Call call);void onCallRemoved(Call call);void onCallStateChanged(Call call, int oldState, int newState);void onConnectionServiceChanged(Call call,ConnectionServiceWrapper oldService,ConnectionServiceWrapper newService);void onIncomingCallAnswered(Call call);void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage);void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState);void onRingbackRequested(Call call, boolean ringback);void onIsConferencedChanged(Call call);void onIsVoipAudioModeChanged(Call call);void onVideoStateChanged(Call call, int previousVideoState, int newVideoState);void onCanAddCallChanged(boolean canAddCall);void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);void onHoldToneRequested(Call call);void onExternalCallChanged(Call call, boolean isExternalCall);void onDisconnectedTonePlaying(boolean isTonePlaying);void onConnectionTimeChanged(Call call);void onConferenceStateChanged(Call call, boolean isConference);}

在Telecom 应用加载的初始化过程中,将创建CallsManagerListener 对象,并增加到CallsManager 对象的 mlisteners 列表中;而通话的相关状态或属性发生改变时, CallsManager 将遍历mlisteners 列表,进行on XXX的消息回调,其代码逻辑总结如下:

Ca llsManagerlistener 接口定义在Ca ll sManager 类中, CallsManagerListenerBase 类实现了此接口的所有方法,而且这些方法都没有任何的业务逻辑代码。在面向对象编程中,使用多态的一种典型方式是子类可根据业务需要选择父类中的方法进行重写。

CallsManagerlistenerBase 所有子类的作用及重写的方法, 总结如表4-1 所示。

2) Call.Listener

  • /packages/services/Telecomm/src/com/android/server/telecom/Call.java

拨号流程或是来电流程中,都会创建com.android.server.telecom. Call 对象,此类中定义了Listener 接口,主要有以下几个方法:

-------Call 类
106       * Listener for events on the call.
107       */
108      @VisibleForTesting
109      public interface Listener {
110          void onSuccessfulOutgoingCall(Call call, int callState);
111          void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause);
112          void onSuccessfulIncomingCall(Call call);---------
151      public abstract static class ListenerBase implements Listener {
152          @Override
153          public void onSuccessfulOutgoingCall(Call call, int callState) {}
154          @Override
155          public void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause) {}
-------CallsManager类
------------
151  @VisibleForTesting
152  public class CallsManager extends Call.ListenerBase

CallsManager 作为Call.Listener 接口的子类,由Call 对象触发mlistenersCall 对象变化的消息回调, CallsManager 对象将通过自己的 mlisteners ,继续发出Call 对象变化的消息回调,而这一次的消息回调将接收并处理12 个对象;因此,可以将CallsManager 看作Call 对象变化 Listener 消息回调的消息中转站,将Call. Listener 和CallsManagerlistener 这两个Listener 紧密联系在一起。

3) CallsManager 工作机制

上图大致包含了CallsManager、Call、CallsManagerListener的工作机制:
Telecom启动之时就创建了CallsManager,而CallsManager在构造器内就将通话相关功能类注册到了监听列表中。在发生通话时(MT或MO),CallsManager首先创建出Call并回调所有观察者的对应方法,在Call状态更新时,会回调CallsManager相关方法,然后CallsManager会对Call进行相关处理,并会回调所有观察者的对应方法。

4) CreateConnectionResponse

CreateConnectionResponse 接口定义了两个方法: handleCreateConnectionSuccess 和handleCreateConnectionFailure ,

它总共有两个子类: Call 和CreateConnectionProcessor ,

Call 和CreateConnectionProcessor  都是 CreateConnectionResponse 接口对象。

不论拨号流程还是来电流程, Telecom 在Call 对象创建完成后, 都调用其 startCreateConnection 方法最终完成绑定 IConnectionService 服务相关的操作;在此过程中将涉及CreateConnectionResponse 接口对象的创建和传递过程,代码框架总结如下。

5)总结 Listener 消息

在Telecom 应用中主要处理两种消息类型:顺时针方向下发的通话控制消息 和 逆时针方向上报的通话状态变化消息。

而Listener 消息回调承载着上报消息的业务处理逻辑,其应用场景是ConnectionServiceWrapper 的Adapter 服务对象接收到TeleService 应用的接口调用,

通知当前Connection 和Call 的状态或属性发生的变化,再经过一系列的Listener 消息回调处理,最终由lnCallController 创建ParcelableCall 对象,使用 llnCallService 服务接口调用发送给Dialer 应用。

可见这些Listener 消息处理在Telecom 应用中的重要性,继续对CallsManager.Listener、Call.Listener 和 CreateConnectionResponse 三个核心消息回调的分析结果进行汇总和总结,形成Telecom 应用中消息回调的全貌

两条消息回调通道的调用过程,都会调用CallsManager 对象的setCallState 方法更新Telecom应用中的Call 属性

调用过程如下:

//第-条消息回调通道的调用过程【Telephony上报】
ConnectionServiceWrapper . mAdapter.handleCreateConnectionComplete
-> mPendingResponses(CreateConnectionProcessor) . handleCreateConnectionSuccess
- > mCallResponse (Call). handleCreateConnectionSuccess

- > mListeners(CallsManager) . onSuccessfulXXXCall->setCallState

//第二条消息回调通道的调用过程【与InCallui交互】
ConnectionServiceWrapper . mAdapter.setActive
- > mCallsManager . markCallAsActive >setCallState
//CallsManager 对象的调用过程
CallsManager.setCallState
- > InCallController.onCallStateChanged - > updateCall- >inCallService.updateCall

6)耳机事件

关注 MediaSession 类

链接

安卓电话交互桥梁 Telecom【System进程】相关推荐

  1. win7 win10下80端口被System进程占用的解决方法

    用如下方法可以解决System进程占用80端口的问题: 打开RegEdit:开始-运行-输入regedit-调出注册表 找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentContr ...

  2. 安卓上为什么不能用system.io.file读取streammingAssets目录下的文件

    安卓上为什么不能用system.io.file读取streammingAssets目录下的文件 首先,看文档: Streaming Assets Most assets in Unity are co ...

  3. Zygote和System进程的启动过程

    ##init脚本的启动 +------------+ +-------+ +-----------+ |Linux Kernel+--> |init.rc+-> |app_process| ...

  4. 安卓电话和网络开发全解:电话硬件检测、电话服务信息、sim信息、网络服务信息、数据连接和数据传输信息、电话状态监听

    全栈工程师开发手册 (作者:栾鹏) 安卓教程全解 安卓电话和网络开发全解,包括电话硬件检测.电话服务信息.sim信息.网络服务信息.数据连接和数据传输信息.通过phone state listener ...

  5. 【旧文章搬运】为什么win32k.sys在System进程空间无法访问

    原文发表于百度空间,2010-01-02 ========================================================================== 玩过Sh ...

  6. 为什么win32k.sys在System进程空间无法访问

    2010年01月02日 21:21 玩过Shadow SSDT Hook的都知道,在System进程中是无法访问win32k.sys的内存空间的,要想访问必须切换到csrss进程或者任意一个GUI进程 ...

  7. win10系统system进程占用cpu高怎么解决

    Win10系统经常发现任务管理器中的system进程占用了很高的cpu内存,一直在50%左右,这也导致了多项应用程序运行卡顿,本人是家庭激活版本,也在网上搜索win10系统system进程占用cpu高 ...

  8. Windows下80端口被pid为4的System进程占用解决方法

    前言 之前是Windows 7系统,前段时间装了Windows 10,php环境还没来得及搭建.今天折腾了一下,是用nginx+php,端口是80(已经停止了iis服务),nginx就是起不来,十之八 ...

  9. Win10系统System进程占用CPU过高怎么处理,占用30%以上

    我的小黑本本最近安装了Win10系统后,System进程占用CPU过,占用30%以上,导致cpu温度高达90多度. 这个问题困挠我好几个星期,最终我用鲁大师检查驱动,把提示需要更新的都更新了,问题解决 ...

最新文章

  1. 关于深度学习编译器,这些知识你需要知道
  2. eclipse配置虚拟路径后,每次启动tomcat都会虚拟路径失效的问题解决
  3. Android 实现九宫格、点击图片放大全屏浏览等
  4. 如何训练解决问题的能力?
  5. sql倒序查询语句_SQL丨1.基本查询语句复习
  6. BUAA - Team Review Score
  7. iptables_ftp
  8. php页面自分页刷新,详解PHP+AJAX无刷新分页实现方法
  9. 修改centos6.5的时区
  10. apache php mysql_PHP环境搭建(php+Apache+mysql)
  11. XJOI 3266 Dyeing 染色 题解
  12. Mule ESB File Connector轮询单个文件的实现(3)
  13. gb28181协议java_gb28181开发源码
  14. 安装系统时,提示无法安装到这个磁盘,选中的磁盘具有MBR分区表,在EFI系统上,windows只能安装到GPT磁盘的问题
  15. 上海航芯 | 从STM32F103到ACM32F403的U盘程序移植工程
  16. 微信淘宝客机器人分享
  17. 在计算机里看不到硬盘的信息,检测不到硬盘,详细教您系统里找不到硬盘该怎么办...
  18. Android加载服务器的静态图片文件
  19. wifidog 整体分析
  20. 黑苹果双系统时间不一致_解决 Windows/macOS 双系统时间不同步问题

热门文章

  1. Cell:破解肠道菌群调节宿主长寿之谜(专家点评)
  2. RK3399平台开发系列讲解(中断篇)中断控制器(Generic Interrupt Controller)
  3. BitPay将支持使用XRP购买礼品卡在连锁零售商和餐厅消费
  4. [转]计算机科学经典论文
  5. java虚拟机JVM基础
  6. PCS-943开关量开入回路
  7. 电子版权认证证书app上架专用软件著作权认证证书有什么用?准备哪些材料?
  8. 航天器的组成之航天器平台!
  9. 2013园博会工程充分展现了立体绿化
  10. 电脑使用技巧提升篇3:调整电脑桌面路径位置