Framework基礎(chǔ):傳感器服務的通信流程(binder與socket)

么多.png

傳感器服務弯淘,是通過binder進行業(yè)務控制榕吼,使用socket進行傳感器感應數(shù)據(jù)傳輸薄料。

客戶端是/frameworks/native/libs/gui/SensorManager.cpp
服務端是/frameworks/native/services/sensorservice/SensorService.cpp

native binder套路圖.png
通道建立.png

我們走一下使能sensor上電的過程吧狂丝!

/frameworks/base/core/java/android/hardware/SystemSensorManager.java
首先進入enableSensor,其中nSensorEventQueue是jni層創(chuàng)建SensorEventQueue的返回值童本,標識一個queue真屯。

        private int enableSensor(
                Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
            if (nSensorEventQueue == 0) throw new NullPointerException();
            if (sensor == null) throw new NullPointerException();
            return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
                    maxBatchReportLatencyUs);
        }

調(diào)用到j(luò)ni接口nativeEnableSensor

static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
                               jint maxBatchReportLatency) {
    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
                                                         0);
}

進入receiver的getSensorEventQueue()->enableSensor,看看receiver的定義穷娱,他是在構(gòu)建native層的SensorEventQueue是創(chuàng)建的绑蔫,里面保存著隊列SensorEventQueue

class Receiver : public LooperCallback {
    sp<SensorEventQueue> mSensorQueue;
    sp<MessageQueue> mMessageQueue;
    jobject mReceiverWeakGlobal;
    jfloatArray mScratch;
public:
    Receiver(const sp<SensorEventQueue>& sensorQueue,
            const sp<MessageQueue>& messageQueue,
            jobject receiverWeak, jfloatArray scratch) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        mSensorQueue = sensorQueue;
        mMessageQueue = messageQueue;
        mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);
        mScratch = (jfloatArray)env->NewGlobalRef(scratch);
    }
    ~Receiver() {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        env->DeleteGlobalRef(mReceiverWeakGlobal);
        env->DeleteGlobalRef(mScratch);
    }
    sp<SensorEventQueue> getSensorEventQueue() const {
        return mSensorQueue;
    }

/frameworks/native/libs/gui/SensorEventQueue.cpp
進而進入SensorEventQueue的enableSensor方法运沦,他是通過服務端與客戶端的連接SensorEventConnection來發(fā)送數(shù)據(jù)給服務端SensorService。

status_t SensorEventQueue::enableSensor(Sensor const* sensor) const {
    return mSensorEventConnection->enableDisable(sensor->getHandle(), true, 0, 0, false);
}

SensorEventConnection也是基于binder架構(gòu)的配深,客戶端的SensorEventConnection其實是個代理携添,不是真正的SensorEventConnection,真正的SensorEventConnection在服務器端呢篓叶。
/frameworks/native/services/sensorservice/SensorService.cpp

sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName,
        int requestedMode, const String16& opPackageName) {
    uid_t uid = IPCThreadState::self()->getCallingUid();
    sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName,
            requestedMode == DATA_INJECTION, opPackageName)); 
   //創(chuàng)建一個SensorEventConnection
    return result;
}

//SensorEventConnection的構(gòu)造函數(shù)
SensorService::SensorEventConnection::SensorEventConnection(
        const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
        const String16& opPackageName)
    : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
      mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
      mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) {
    mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
    mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
    mTotalAcksNeeded = mTotalAcksReceived = 0;
#endif
}

接下來會利用這個代理的SensorEventConnection構(gòu)造一個隊列SensorEventQueue烈掠,直接傳入代理SensorEventConnection來構(gòu)造隊列。

sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
   .......
    sp<SensorEventQueue> queue;
    queue = new SensorEventQueue(connection);
    return queue;
}

真正的傳感器測量數(shù)據(jù)傳輸不在SensorEventConnection澜共,而是利用一個管道BitTube向叉,他用socket實現(xiàn)锥腻,便于大量數(shù)據(jù)傳輸嗦董,每個SensorEventConnection都配套一個BitTube,BitTube在SensorEventConnection的構(gòu)造函數(shù)中構(gòu)建了瘦黑。那這個東西在服務器端構(gòu)建了京革,如何傳給客戶端呢?是在SensorEventQueue的onFirstRef()函數(shù)中產(chǎn)生的,利用代理的SensorEventConnection來遠程調(diào)用getSensorChannel幸斥,最后生成本地的管道BitTube匹摇。

void SensorEventQueue::onFirstRef()
{
    mSensorChannel = mSensorEventConnection->getSensorChannel();
}

/frameworks/native/libs/gui/ISensorEventConnection.cpp
在客戶端調(diào)用transact,發(fā)送GET_SENSOR_CHANNEL

    //客戶端調(diào)用transact
    virtual sp<BitTube> getSensorChannel() const
    {
        Parcel data, reply;
        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
        remote()->transact(GET_SENSOR_CHANNEL, data, &reply);
        return new BitTube(reply);
    }

        //服務器端處理消息
        case GET_SENSOR_CHANNEL: {
            CHECK_INTERFACE(ISensorEventConnection, data, reply);
            sp<BitTube> channel(getSensorChannel());
            channel->writeToParcel(reply);
            return NO_ERROR;
        }

最后甲葬,服務器和客戶端就利用這個管道BitTube進行通信了廊勃。

但是,然并卵经窖,使能上電并不需要傳輸傳感器數(shù)據(jù),最后會在服務器端SensorService上了下電而已F碌妗!

status_t SensorService::enable(const sp<SensorEventConnection>& connection,
        int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
        const String16& opPackageName)
{
    ......
    BatteryService::enableSensor(connection->getUid(), handle);
    return err;
    .....
}

參考:
Service與Android系統(tǒng)設(shè)計(6)--- Native Service
Android BitTube進程間數(shù)據(jù)傳遞
Android6.0 Sensor架構(gòu)和問題分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末画侣,一起剝皮案震驚了整個濱河市冰悠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌配乱,老刑警劉巖溉卓,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異搬泥,居然都是意外死亡桑寨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門忿檩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尉尾,“玉大人,你說我怎么就攤上這事休溶〈蓿” “怎么了扰她?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芭碍。 經(jīng)常有香客問我徒役,道長,這世上最難降的妖魔是什么窖壕? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任忧勿,我火速辦了婚禮,結(jié)果婚禮上瞻讽,老公的妹妹穿的比我還像新娘鸳吸。我一直安慰自己,他們只是感情好速勇,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布晌砾。 她就那樣靜靜地躺著,像睡著了一般烦磁。 火紅的嫁衣襯著肌膚如雪养匈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天都伪,我揣著相機與錄音呕乎,去河邊找鬼。 笑死陨晶,一個胖子當著我的面吹牛猬仁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播先誉,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼湿刽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谆膳?” 一聲冷哼從身側(cè)響起叭爱,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漱病,沒想到半個月后买雾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡杨帽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年漓穿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片注盈。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡晃危,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情僚饭,我是刑警寧澤震叮,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站鳍鸵,受9級特大地震影響苇瓣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜偿乖,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一击罪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贪薪,春花似錦媳禁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至槽唾,卻和暖如春丧枪,著一層夾襖步出監(jiān)牢的瞬間光涂,已是汗流浹背庞萍。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留忘闻,地道東北人钝计。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像齐佳,于是被迫代替她去往敵國和親私恬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

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