微信 Mars Android Sample 源碼分析

首發(fā)地址:微信 Mars Android Sample 源碼分析

注:為了避免看得懵逼(當(dāng)然可能是我寫(xiě)得不好~)旭从,建議最好先下載代碼谊路,運(yùn)行完看到效果圖后瓣窄,再結(jié)合項(xiàng)目代碼看“詳細(xì)分析”部分……

零宗挥、前言

Mars 是微信官方開(kāi)源的跨平臺(tái)跨業(yè)務(wù)的終端基礎(chǔ)組件,具有高質(zhì)量網(wǎng)絡(luò)連接模塊(長(zhǎng)短連接怔毛、智能心跳機(jī)制)、高性能日志模塊和網(wǎng)絡(luò)監(jiān)測(cè)組件等腾降。而整個(gè) Android Sample 是基于 Mars 開(kāi)發(fā)的一個(gè) demo拣度,包含提供了以下功能:

  • 基于TCP長(zhǎng)連接的聊天室體驗(yàn)。
  • 數(shù)據(jù)通信成功率螃壤、耗時(shí)抗果、流量的展示。
  • 網(wǎng)絡(luò)狀況檢測(cè)結(jié)果展示映穗。

先下載 Mars 代碼:https://github.com/Tencent/mars

一窖张、本地運(yùn)行 Server 端

具體如何運(yùn)行 Server 端,參照官方wiki:Mars Sample 使用說(shuō)明

二蚁滋、修改 Android Sample

下面說(shuō)下Android 端該如何修改源碼連接到本地服務(wù)器

  • 1.全局搜索marsopen.cn宿接,修改替換為localhost
  • 2.在保證 app/build.gradleuseLocalMarsWrapper = true的情況下,在 wrapper module 下修改 com.tencent.mars.sample.wrapper.service. MarsServiceStub.java 的 dns 解析的地址為本地主機(jī)的 IP 地址 (wiki 上沒(méi)寫(xiě)清楚)
    @Override
    public String[] onNewDns(String host) {
        // No default new dns support
        return new String[]{"192.168.24.193"}; //替換為本地主機(jī)的 IP 地址
    }

三辕录、運(yùn)行后聊天效果

IM 聊天效果
IM 服務(wù)端終端日志

四睦霎、整體概述

  1. 由項(xiàng)目結(jié)構(gòu)可知 sample 分為兩部分,app 和 wrapper(當(dāng)然也可以用依賴的方式來(lái)使用)走诞,數(shù)據(jù)格式使用的是google開(kāi)源的 protobuf副女,它具有高效、數(shù)據(jù)量小的特性(目前版本為 proto3蚣旱,Android 開(kāi)發(fā)推薦使用 protobuf-lite 版本碑幅,使用方法

  2. Mars Android 接入指南 · Tencent/mars Wiki · GitHub有這樣一條介紹:

目前 gradle 接入支持兩種方式:mars-core 和 mars-wrapper戴陡。只是做個(gè) sample 的話建議可以使用 mars-wrapper, 但是如果在實(shí)際 App 中使用 mars沟涨,建議使用 mars-core 或本地編譯恤批。
怎么理解這句話??jī)煞N接入有什么不同裹赴?
從 sample 中 mars-wrapper(下面簡(jiǎn)稱為 wrapper) 的源碼可以看出 wrapper 只是對(duì) mars-core 進(jìn)行了再次封裝喜庞,wrapper 庫(kù)本質(zhì)還是依賴 mars-core 庫(kù)的,所以微信團(tuán)隊(duì)不建議實(shí)際App 中接入 wrapper ( 它只是微信官方提供對(duì) mars-core 使用的一種方式棋返,不過(guò)具有很好的參考價(jià)值)

  1. 另外延都,有 wrapper 的 manifest 可知,IM 服務(wù)模塊是運(yùn)行在獨(dú)立的進(jìn)程的睛竣,所以同時(shí)會(huì)涉及到 AIDL 多進(jìn)程通信方面技術(shù)晰房。
 <application>
        <service
            android:name=".service.MarsServiceNative"
            android:process=":marsservice" />

        <!--注冊(cè)一個(gè)網(wǎng)絡(luò)切換的廣播接收器(源碼上實(shí)現(xiàn)的)-->
        <receiver
            android:name="com.tencent.mars.BaseEvent$ConnectionReceiver"
            android:process=":marsservice" />
    </application>

五、詳細(xì)分析

1. 先從 ConversationActivity 獲取初始的會(huì)話列表的請(qǐng)求開(kāi)始

      private NanoMarsTaskWrapper<Main.ConversationListRequest, Main.ConversationListResponse> taskGetConvList = null;

    private void updateConversationTopics() {
        if (taskGetConvList != null) {
            MarsServiceProxy.cancel(taskGetConvList);
        }

        textView.setVisibility(View.INVISIBLE);
        progressBar.setVisibility(View.VISIBLE);

        swipeRefreshLayout.setRefreshing(true);

        taskGetConvList = new NanoMarsTaskWrapper<Main.ConversationListRequest, Main.ConversationListResponse>(
                new Main.ConversationListRequest(),
                new Main.ConversationListResponse()
        ) {

            private List<Conversation> dataList = new LinkedList<>();

            @Override
            public void onPreEncode(Main.ConversationListRequest req) {
                req.type = conversationFilterType;
                req.accessToken = ""; // TODO:
            }

            @Override
            public void onPostDecode(Main.ConversationListResponse response) {

            }

            @Override
            public void onTaskEnd(int errType, int errCode) {
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        if (response != null) {
                            for (Main.Conversation conv : response.list) {
                                dataList.add(new Conversation(conv.name, conv.topic, conv.notice));
                            }
                        }

                        if (!dataList.isEmpty()) {
                            progressBar.setVisibility(View.INVISIBLE);
                            conversationListAdapter.list.clear();
                            conversationListAdapter.list.addAll(dataList);
                            conversationListAdapter.notifyDataSetChanged();

                            swipeRefreshLayout.setRefreshing(false);

                        } else {
                            Log.i(TAG, "getconvlist: empty response list");
                            progressBar.setVisibility(View.INVISIBLE);
                            textView.setVisibility(View.VISIBLE);
                        }
                    }
                });
            }

        };

        MarsServiceProxy.send(taskGetConvList.setHttpRequest(CONVERSATION_HOST, "/mars/getconvlist"));
    }

執(zhí)行步驟:

  • 創(chuàng)建一個(gè) NanoMarsTaskWrapper 對(duì)象酵颁,里面主要包含 onPreEncode嫉你,onPostDecode 和onTaskEnd 等方法,分別是編碼傳輸前躏惋,接收數(shù)據(jù)解碼后和任務(wù)結(jié)束后的回調(diào)幽污;
  • 設(shè)置 NanoMarsTaskWrapper 的 http 地址
  • 通過(guò) MarsServiceProxy.send 方法執(zhí)行發(fā)送請(qǐng)求;

初步了解執(zhí)行步驟后簿姨,再詳細(xì)了解 MarServiceProxy 和 NanoMarTaskWrapper 的實(shí)現(xiàn)距误,它們?yōu)槭裁磿?huì)有這樣的功能。

2. NanoMarTaskWrapper

顧名思義扁位,NanoMarTaskWrapper 是一個(gè)任務(wù)的包裝器

public abstract class NanoMarsTaskWrapper<T extends MessageNano, R extends MessageNano> extends AbstractTaskWrapper {

    private static final String TAG = "Mars.Sample.NanoMarsTaskWrapper";

    protected T request;
    protected R response;

    public NanoMarsTaskWrapper(T req, R resp) {
        super();

        this.request = req;
        this.response = resp;
    }

    @Override
    public byte[] req2buf() {
        try {
            onPreEncode(request);

            final byte[] flatArray = new byte[request.getSerializedSize()];
            final CodedOutputByteBufferNano output = CodedOutputByteBufferNano.newInstance(flatArray);
            request.writeTo(output);

            Log.d(TAG, "encoded request to buffer, [%s]", MemoryDump.dumpHex(flatArray));

            return flatArray;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return new byte[0];
    }

    @Override
    public int buf2resp(byte[] buf) {
        try {
            Log.d(TAG, "decode response buffer, [%s]", MemoryDump.dumpHex(buf));

            response = MessageNano.mergeFrom(response, buf);
            onPostDecode(response);
            return StnLogic.RESP_FAIL_HANDLE_NORMAL;

        } catch (Exception e) {
            Log.e(TAG, "%s", e);
        }

        return StnLogic.RESP_FAIL_HANDLE_TASK_END;
    }

    public abstract void onPreEncode(T request);

    public abstract void onPostDecode(R response);
}
  • 1)繼承自AbstractTaskWrapper
  • 2)創(chuàng)建時(shí)會(huì)同時(shí)創(chuàng)建繼承自 MessageNano(protobuf 的消息數(shù)據(jù)類) 的 request 和 response 數(shù)據(jù)模型准潭;
  • 3)處理編解碼的兩個(gè)方法,req2buf 和 buf2resp域仇,也就是字節(jié)流數(shù)組和 protobuf 對(duì)象的轉(zhuǎn)換刑然,涉及到 MessageNano.writeToMessageNano.mergeFrom的使用,這方面的具體實(shí)現(xiàn)不需要我們?nèi)チ私庀疚瘢珿oogle 的 protobuf 已經(jīng)幫我們生成代碼完成好了

再看看 AbstractTaskWrapper 是怎樣實(shí)現(xiàn)的

public abstract class AbstractTaskWrapper extends MarsTaskWrapper.Stub {

    private Bundle properties = new Bundle();

    public AbstractTaskWrapper() {

        // Reflects task properties 通過(guò)自身(繼承該類的類)標(biāo)注的注解泼掠,用反射獲取任務(wù)的配置信息
        final TaskProperty taskProperty = this.getClass().getAnnotation(TaskProperty.class);
        if (taskProperty != null) {
            setHttpRequest(taskProperty.host(), taskProperty.path());
            setShortChannelSupport(taskProperty.shortChannelSupport());
            setLongChannelSupport(taskProperty.longChannelSupport());
            setCmdID(taskProperty.cmdID());
        }
    }

    @Override
    public Bundle getProperties() {
        return properties;
    }

    @Override
    public abstract void onTaskEnd(int errType, int errCode);

    public AbstractTaskWrapper setHttpRequest(String host, String path) {
        properties.putString(MarsTaskProperty.OPTIONS_HOST, ("".equals(host) ? null : host));
        properties.putString(MarsTaskProperty.OPTIONS_CGI_PATH, path);

        return this;
    }

    public AbstractTaskWrapper setShortChannelSupport(boolean support) {
        properties.putBoolean(MarsTaskProperty.OPTIONS_CHANNEL_SHORT_SUPPORT, support);
        return this;
    }

    public AbstractTaskWrapper setLongChannelSupport(boolean support) {
        properties.putBoolean(MarsTaskProperty.OPTIONS_CHANNEL_LONG_SUPPORT, support);
        return this;
    }

    public AbstractTaskWrapper setCmdID(int cmdID) {
        properties.putInt(MarsTaskProperty.OPTIONS_CMD_ID, cmdID);
        return this;
    }

    @Override
    public String toString() {
        return "AbsMarsTask: " + BundleFormat.toString(properties);
    }
}

抽象的 AbstractTaskWrapper 繼承自 MarTaskWrapper.Stub (MarsTaskWrapper.aidl 生成的代碼),它主要通過(guò)注解類 TaskProperty 設(shè)置了任務(wù)的配置信息 properties(如主機(jī)名垦细、url路徑择镇、是否支持長(zhǎng)短鏈接和指令 id),

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
public @interface TaskProperty {

    String host() default "";

    String path();

    boolean shortChannelSupport() default true;

    boolean longChannelSupport() default false;

    int cmdID() default -1;
}

再回到剛開(kāi)始的發(fā)送消息的 MarsServiceProxy 類

3. MarsServiceProxy

public class MarsServiceProxy implements ServiceConnection {
      //……
    private MarsService service = null;  
    public static MarsServiceProxy inst;
    private LinkedBlockingQueue<MarsTaskWrapper> queue = new LinkedBlockingQueue<>();
      private MarsServiceProxy() {
        worker = new Worker();
        worker.start();
    }

    public static void init(Context context, Looper looper, String packageName) {
        if (inst != null) {
            // TODO: Already initialized
            return;
        }

        gContext = context.getApplicationContext();

        gPackageName = (packageName == null ? context.getPackageName() : packageName);
        gClassName = SERVICE_DEFAULT_CLASSNAME;

        inst = new MarsServiceProxy();
    }

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder binder) {
        Log.d(TAG, "remote mars service connected");

        try {
            service = MarsService.Stub.asInterface(binder);
            service.registerPushMessageFilter(filter);
            service.setAccountInfo(accountInfo.uin, accountInfo.userName);

        } catch (Exception e) {
            service = null;
        }
    }
      //……
    private static class Worker extends Thread {

        @Override
        public void run() {
            while (true) {
                inst.continueProcessTaskWrappers();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    //
                }
            }
        }
    }
}

MarsServiceProxy 只是一個(gè)單例的 ServiceConnection,不過(guò)它應(yīng)該具有代理某種 Service的功能(ServiceConnection會(huì)和 Service綁定)括改,由定義的變量和onServiceConnected中的調(diào)用可知腻豌,它關(guān)聯(lián)了 MarsService,但是 MarsService 只是一個(gè) AIDL ,不是真正的服務(wù)吝梅,這個(gè)稍后再說(shuō)
MarsServiceProxy 是在SampleApplication 的 onCreate調(diào)用的時(shí)候初始化的

// NOTE: MarsServiceProxy is for client/caller
// Initialize MarsServiceProxy for local client, can be moved to other place
MarsServiceProxy.init(this, getMainLooper(), null);

當(dāng)調(diào)用send 方法發(fā)送任務(wù)時(shí)虱疏,

    public static void send(MarsTaskWrapper marsTaskWrapper) {
        inst.queue.offer(marsTaskWrapper);
    }

queue 是一個(gè) LinkedBlockingQueue<MarsTaskWrapper>線程安全的隊(duì)列,緩存了所有的MarsTaskWrapper 任務(wù)憔涉。
那將任務(wù)放進(jìn)隊(duì)列后订框,什么時(shí)候執(zhí)行呢析苫?由上面代碼可以看到 MarsServiceProxy 創(chuàng)建時(shí)會(huì)啟動(dòng)一個(gè) Worker 線程兜叨,線程會(huì)每隔50ms 執(zhí)行調(diào)用inst.continueProcessTaskWrappers();方法

     private void continueProcessTaskWrappers() {
        try {
            if (service == null) {  //服務(wù)為 null時(shí),重新開(kāi)啟
                Log.d(TAG, "try to bind remote mars service, packageName: %s, className: %s", gPackageName, gClassName);
                Intent i = new Intent().setClassName(gPackageName, gClassName);
                gContext.startService(i);
                if (!gContext.bindService(i, inst, Service.BIND_AUTO_CREATE)) {  //注意衩侥,此處有個(gè) Service 綁定的判斷
                    Log.e(TAG, "remote mars service bind failed");
                }

                // Waiting for service connected
                return;
            }

            MarsTaskWrapper taskWrapper = queue.take(); //取出隊(duì)列中的 MarsTask
            if (taskWrapper == null) { //任務(wù)為空国旷,跳出方法的執(zhí)行
                // Stop, no more task
                return;
            }

            try {
                Log.d(TAG, "sending task = %s", taskWrapper);
                final String cgiPath = taskWrapper.getProperties().getString(MarsTaskProperty.OPTIONS_CGI_PATH);
                final Integer globalCmdID = GLOBAL_CMD_ID_MAP.get(cgiPath);   
                if (globalCmdID != null) {
                    taskWrapper.getProperties().putInt(MarsTaskProperty.OPTIONS_CMD_ID, globalCmdID);
                    Log.i(TAG, "overwrite cmdID with global cmdID Map: %s -> %d", cgiPath, globalCmdID);
                }

                final int taskID = service.send(taskWrapper, taskWrapper.getProperties());
                // NOTE: Save taskID to taskWrapper here
                taskWrapper.getProperties().putInt(MarsTaskProperty.OPTIONS_TASK_ID, taskID);

            } catch (Exception e) { // RemoteExceptionHandler
                e.printStackTrace();
            }

        } catch (Exception e) {
            //
        }
    }

這個(gè)方法里面會(huì)從任務(wù)隊(duì)列取出一個(gè)任務(wù),然后最終會(huì)通過(guò) MarsService.send 方法發(fā)送消息任務(wù)茫死,并保存任務(wù) id

另外這個(gè)方法開(kāi)始還有啟動(dòng)服務(wù)的判斷跪但,由gClassName = SERVICE_DEFAULT_CLASSNAME = "com.tencent.mars.sample.wrapper.service.MarsServiceNative"知道,啟動(dòng)的服務(wù)是MarsServiceNative峦萎,那 MarsServiceNative 是怎樣和 MarsServiceProxy 關(guān)聯(lián)起來(lái)的呢屡久?

再看 MarsServiceProxy 的 onServiceConnected 方法,MarsService 的初始化是通過(guò)MarsService.Stub.asInterface(binder)關(guān)聯(lián)了 MarsServiceProxy 的 IBinder

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder binder) {
        Log.d(TAG, "remote mars service connected");

        try {
            service = MarsService.Stub.asInterface(binder);
            service.registerPushMessageFilter(filter);
            service.setAccountInfo(accountInfo.uin, accountInfo.userName);

        } catch (Exception e) {
            service = null;
        }
    }

那哪個(gè)類實(shí)現(xiàn)了 MarsService 的方法呢爱榔?查看 MarsServiceNative 源碼就能明白了被环,它同時(shí)實(shí)現(xiàn) MarsService,間接和 MarsServiceProxy 形成強(qiáng)關(guān)聯(lián)

public class MarsServiceNative extends Service implements MarsService {

    private static final String TAG = "Mars.Sample.MarsServiceNative";

    private MarsServiceStub stub;
    //mars服務(wù)配置工廠
    private static MarsServiceProfileFactory gFactory = new MarsServiceProfileFactory() {
        @Override
        public MarsServiceProfile createMarsServiceProfile() {
            return new DebugMarsServiceProfile();
        }
    };

      //……

    @Override
    public IBinder asBinder() {
        return stub;
    }

    /**
     * 創(chuàng)建運(yùn)行 Mars 的服務(wù)時(shí)就初始化 STN (建議在程序啟動(dòng)時(shí)或者使用網(wǎng)絡(luò)之前調(diào)用)
     */
    @Override
    public void onCreate() {
        super.onCreate();

        final MarsServiceProfile profile = gFactory.createMarsServiceProfile();
        stub = new MarsServiceStub(this, profile);

        // set callback
        AppLogic.setCallBack(stub);
        StnLogic.setCallBack(stub);
        SdtLogic.setCallBack(stub);

        // Initialize the Mars PlatformComm
        Mars.init(getApplicationContext(), new Handler(Looper.getMainLooper()));

        // Initialize the Mars
        StnLogic.setLonglinkSvrAddr(profile.longLinkHost(), profile.longLinkPorts());
        StnLogic.setShortlinkSvrAddr(profile.shortLinkPort());
        StnLogic.setClientVersion(profile.productID());
        Mars.onCreate(true);

        StnLogic.makesureLongLinkConnected();

        //
        Log.d(TAG, "mars service native created");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return stub;
    }
}

MarsServiceNative 是使用 mars-core 的關(guān)鍵類详幽,同時(shí)它也是一個(gè) Service 類筛欢,運(yùn)行在獨(dú)立進(jìn)程中,主要負(fù)責(zé)了以下功能:

  • 創(chuàng)建配置信息類 MarsServiceProfile唇聘,并在 StnLogic 設(shè)置相關(guān)信息版姑;
  • 實(shí)例化一個(gè) MarsServiceStub;
  • 設(shè)置了 AppLogic, StnLogic, SdtLogic 的回調(diào)迟郎;
  • 初始化 Mars剥险;
  • 確定 StnLogic 的長(zhǎng)連接StnLogic.makesureLongLinkConnected();
    既然 MarsServiceNative 設(shè)置了 AppLogic, StnLogic, SdtLogic 的回調(diào),那再看看 MarsServiceStub 是如何實(shí)現(xiàn)它們接口的

4. MarsServiceStub

先看發(fā)送消息的 send 方法

public class MarsServiceStub extends MarsService.Stub implements StnLogic.ICallBack, SdtLogic.ICallBack, AppLogic.ICallBack {

    private static final String TAG = "Mars.Sample.MarsServiceStub";

    private final MarsServiceProfile profile;

    private AppLogic.AccountInfo accountInfo = new AppLogic.AccountInfo();

      //……    
    
    private ConcurrentLinkedQueue<MarsPushMessageFilter> filters = new ConcurrentLinkedQueue<>();

    private int clientVersion = 200;

    public MarsServiceStub(Context context, MarsServiceProfile profile) {
        this.context = context;
        this.profile = profile;
    }

    private static final int FIXED_HEADER_SKIP = 4 + 2 + 2 + 4 + 4;

    private static Map<Integer, MarsTaskWrapper> TASK_ID_TO_WRAPPER = new ConcurrentHashMap<>();

    @Override
    public int send(final MarsTaskWrapper taskWrapper, Bundle taskProperties) throws RemoteException {
        final StnLogic.Task _task = new StnLogic.Task(StnLogic.Task.EShort, 0, "", null);  //初始化為

        // Set host & cgi path
        final String host = taskProperties.getString(MarsTaskProperty.OPTIONS_HOST);
        final String cgiPath = taskProperties.getString(MarsTaskProperty.OPTIONS_CGI_PATH);
        _task.shortLinkHostList = new ArrayList<>();
        _task.shortLinkHostList.add(host);
        _task.cgi = cgiPath;

        final boolean shortSupport = taskProperties.getBoolean(MarsTaskProperty.OPTIONS_CHANNEL_SHORT_SUPPORT, true);
        final boolean longSupport = taskProperties.getBoolean(MarsTaskProperty.OPTIONS_CHANNEL_LONG_SUPPORT, false);
        if (shortSupport && longSupport) {
            _task.channelSelect = StnLogic.Task.EBoth;

        } else if (shortSupport) {
            _task.channelSelect = StnLogic.Task.EShort;

        } else if (longSupport) {
            _task.channelSelect = StnLogic.Task.ELong;

        } else {
            Log.e(TAG, "invalid channel strategy");
            throw new RemoteException("Invalid Channel Strategy");
        }

        // Set cmdID if necessary
        int cmdID = taskProperties.getInt(MarsTaskProperty.OPTIONS_CMD_ID, -1);
        if (cmdID != -1) {
            _task.cmdID = cmdID;
        }

        TASK_ID_TO_WRAPPER.put(_task.taskID, taskWrapper);

        // Send 發(fā)送任務(wù)
        Log.i(TAG, "now start task with id %d", _task.taskID);
        StnLogic.startTask(_task);
        if (StnLogic.hasTask(_task.taskID)) {
            Log.i(TAG, "stn task started with id %d", _task.taskID);

        } else {
            Log.e(TAG, "stn task start failed with id %d", _task.taskID);
        }

        return _task.taskID;
    }
    //……
}
  • 1)創(chuàng)建一個(gè) StnLogic.Task宪肖,并通過(guò) Bundle 傳過(guò)來(lái)的數(shù)據(jù)(主機(jī)名表制、路徑怒允、長(zhǎng)短連接和 cmdId)闸拿,設(shè)置 task;
  • 2)保存 taskID 和 MarsTaskWrapper 的映射關(guān)系秋泄;
  • 3)調(diào)用 StnLogic.startTask(_task) 啟動(dòng)任務(wù)執(zhí)行阱持,最后返回 taskID;
    具體的邏輯實(shí)現(xiàn)還是在 mars-core 和底層的 C++ 源碼中夭拌,這個(gè)以后研究到底層源碼再說(shuō)。
    在 mars-core 大概看下 StnLogic.ICallBack 接口有哪些方法:
/**
     * Created by caoshaokun on 16/2/1.
     *
     * APP使用信令通道必須實(shí)現(xiàn)該接口
     * 接口用于信令通道處理完后回調(diào)上層
     */
    public interface ICallBack {
        /**
         * SDK要求上層做認(rèn)證操作(可能新發(fā)起一個(gè)AUTH CGI)
         * @return
         */
        boolean makesureAuthed();

        /**
         * SDK要求上層做域名解析.上層可以實(shí)現(xiàn)傳統(tǒng)DNS解析,或者自己實(shí)現(xiàn)的域名/IP映射
         * @param host
         * @return
         */
        String[] onNewDns(final String host);

        /**
         * 收到SVR PUSH下來(lái)的消息
         * @param cmdid
         * @param data
         */
        void onPush(final int cmdid, final byte[] data);

        /**
         * SDK要求上層對(duì)TASK組包
         * @param taskID    任務(wù)標(biāo)識(shí)
         * @param userContext
         * @param reqBuffer 組包的BUFFER
         * @param errCode   組包的錯(cuò)誤碼
         * @return
         */
        boolean req2Buf(final int taskID, Object userContext, ByteArrayOutputStream reqBuffer, int[] errCode, int channelSelect);

        /**
         * SDK要求上層對(duì)TASK解包
         * @param taskID        任務(wù)標(biāo)識(shí)
         * @param userContext
         * @param respBuffer    要解包的BUFFER
         * @param errCode       解包的錯(cuò)誤碼
         * @return  int
         */
        int buf2Resp(final int taskID, Object userContext, final byte[] respBuffer, int[] errCode, int channelSelect);

        /**
         * 任務(wù)結(jié)束回調(diào)
         * @param taskID            任務(wù)標(biāo)識(shí)
         * @param userContext
         * @param errType           錯(cuò)誤類型
         * @param errCode           錯(cuò)誤碼
         * @return
         */
        int onTaskEnd(final int taskID, Object userContext, final int errType, final int errCode);

        /**
         * 流量統(tǒng)計(jì)
         * @param send
         * @param recv
         */
        void trafficData(final int send, final int recv);

        /**
         * 連接狀態(tài)通知
         * @param status    綜合狀態(tài),即長(zhǎng)連+短連的狀態(tài)
         * @param longlinkstatus    僅長(zhǎng)連的狀態(tài)
         */
        void reportConnectInfo(int status, int longlinkstatus);

        /**
         * SDK要求上層生成長(zhǎng)鏈接數(shù)據(jù)校驗(yàn)包,在長(zhǎng)鏈接連接上之后使用,用于驗(yàn)證SVR身份
         * @param identifyReqBuf    校驗(yàn)包數(shù)據(jù)內(nèi)容
         * @param hashCodeBuffer    校驗(yàn)包的HASH
         * @param reqRespCmdID      數(shù)據(jù)校驗(yàn)的CMD ID
         * @return  ECHECK_NOW(需要校驗(yàn)), ECHECK_NEVER(不校驗(yàn)), ECHECK_NEXT(下一次再詢問(wèn))
         */
        int getLongLinkIdentifyCheckBuffer(ByteArrayOutputStream identifyReqBuf, ByteArrayOutputStream hashCodeBuffer, int[] reqRespCmdID);

        /**
         * SDK要求上層解連接校驗(yàn)回包.
         * @param buffer            SVR回復(fù)的連接校驗(yàn)包
         * @param hashCodeBuffer    CLIENT請(qǐng)求的連接校驗(yàn)包的HASH值
         * @return
         */
        boolean onLongLinkIdentifyResp(final byte[] buffer, final byte[] hashCodeBuffer);

        /**
         * 請(qǐng)求做sync
         */
        void requestDoSync();
        String[] requestNetCheckShortLinkHosts();
        /**
         * 是否登錄
         * @return true 登錄 false 未登錄
         */
        boolean isLogoned();

        void reportTaskProfile(String taskString);
    }

總結(jié)一下:
1.NanoMarsTaskWrapper:涉及編碼前鸽扁、解碼后和任務(wù)結(jié)束后的回調(diào)蒜绽,還有字節(jié)流數(shù)組和 protobuf 對(duì)象的轉(zhuǎn)換等;
2.MarsServiceProxy:是一個(gè) ServiceConnection桶现,涉及消息的發(fā)送和取消等躲雅,作為一個(gè) API 的功能,本質(zhì)是 MarsServiceNative 代理服務(wù)類骡和;
3.MarsServiceNative 是 wrapper 的核心類相赁,里面涉及 Mars 的初始化,設(shè)置了 AppLogic, StnLogic 和 SdtLogic 的回調(diào)等慰于;
4.而 MarsServiceStub 實(shí)現(xiàn)了AppLogic, StnLogic 和 SdtLogic 的回調(diào)接口钮科,維護(hù)了和 mars-core 的調(diào)用等;

其余分析婆赠,可以到我 fork 的 mars 的地址GitHub - navyifanr/mars: (添加注釋分析)下載绵脯。

參考資料:
GitHub - Tencent/mars: Mars is a cross-platform network component developed by WeChat.
微信開(kāi)源mars源碼分析1—上層samples分析 - ameise_w - SegmentFault

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市休里,隨后出現(xiàn)的幾起案子蛆挫,更是在濱河造成了極大的恐慌,老刑警劉巖妙黍,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悴侵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡废境,警方通過(guò)查閱死者的電腦和手機(jī)畜挨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)噩凹,“玉大人巴元,你說(shuō)我怎么就攤上這事⊥匝纾” “怎么了逮刨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)堵泽。 經(jīng)常有香客問(wèn)我修己,道長(zhǎng),這世上最難降的妖魔是什么迎罗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任睬愤,我火速辦了婚禮,結(jié)果婚禮上纹安,老公的妹妹穿的比我還像新娘尤辱。我一直安慰自己砂豌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布光督。 她就那樣靜靜地躺著阳距,像睡著了一般。 火紅的嫁衣襯著肌膚如雪结借。 梳的紋絲不亂的頭發(fā)上筐摘,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音船老,去河邊找鬼咖熟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛努隙,可吹牛的內(nèi)容都是我干的球恤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼荸镊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了堪置?” 一聲冷哼從身側(cè)響起躬存,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舀锨,沒(méi)想到半個(gè)月后岭洲,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坎匿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年盾剩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片替蔬。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡告私,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出承桥,到底是詐尸還是另有隱情驻粟,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布凶异,位于F島的核電站蜀撑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏剩彬。R本人自食惡果不足惜酷麦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喉恋。 院中可真熱鬧沃饶,春花似錦粪摘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至轩褐,卻和暖如春椎咧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背把介。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工勤讽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拗踢。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓脚牍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親巢墅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诸狭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)君纫,斷路器驯遇,智...
    卡卡羅2017閱讀 134,696評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法蓄髓,內(nèi)部類的語(yǔ)法叉庐,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法会喝,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,662評(píng)論 18 399
  • 組件暫支持: 微信陡叠,QQ,圍脖肢执,復(fù)制粘貼 集成微信相關(guān)的分享 按照官方文檔枉阵,集成sdkcompile 'com.t...
    Cosecant閱讀 1,341評(píng)論 3 7
  • 最近因?yàn)楣ぷ鞯男枰恢痹谡砉疚⑿胚\(yùn)營(yíng)中的各種制度,突然發(fā)現(xiàn)微信居然滲透了我生活動(dòng)的方方面面蔚万。出于職業(yè)的需求了解...
    重疊人生閱讀 469評(píng)論 0 0
  • F311+語(yǔ)淳+第七次打卡岭妖,非暴力溝通第三期訓(xùn)練營(yíng) 女兒一直用手機(jī)在看動(dòng)畫(huà)片,我說(shuō)了幾次反璃,我們今天已經(jīng)看完了兩個(gè)動(dòng)...
    語(yǔ)淳珺兒閱讀 275評(píng)論 1 0