Sensor注册流程

一.概要

       我们在android中经常会注册sensor然后监听sensor的数据来做一些特殊的功能,但是之前一直没有关注过整个注册的流程,本文将会告诉你高通855平台中sensor的整个完整的注册流程是什么样子的,先大概总结一下:

APP进程创建一个SensorEventQueue,等待接收system_server发送过来的数据
system_server进程会保存app端的SensorEventQueue,有一个线程会循环的读取[email protected]进程发送过来的消息,当有消息来到时会往APP端的SensorEventQueue中发送sensor 数据,
[email protected]进程会初始化一个socket和子系统通信,并且创建一个线程一直等待BP发送上来的数据,当接收到数据时会发给system_server。
注册流程图参考绿色部分

Sensor注册流程_第1张图片二.APP进程注册:

sensorEventListener = new MySensorEventListener();

//获取方向传感器

Sensor orientationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);// NO.1 获取sensor

sensorManager.registerListener(sensorEventListener, orientationSensor, SensorManager.SENSOR_DELAY_NORMAL); // NO.2注册sensor

 

private final class MySensorEventListener implements SensorEventListener

{

    //可以得到传感器实时测量出来的变化值

    @Override

    public void onSensorChanged(SensorEvent event)

    {

        //得到方向的值

        if(event.sensor.getType()==Sensor.TYPE_ORIENTATION)

        {

            float x = event.values[SensorManager.DATA_X];

            float y = event.values[SensorManager.DATA_Y];

            float z = event.values[SensorManager.DATA_Z];

            orientationView.setText("Orientation: " + x + ", " + y + ", " + z);

        }

    }

    //重写变化

    @Override

    public void onAccuracyChanged(Sensor sensor, int accuracy)

    {

    }

}

首先我们先写一个SensorEventListener,之后sensor有数据之后会回调onSensorChanged/onAccuracyChanged,先不管怎么回调的,先看看注册过程
NO.1获取对应type的sensor

public Sensor getDefaultSensor(int type) {

    // TODO: need to be smarter, for now, just return the 1st sensor

    // NO.1.1 这里是从所有的sensor中获得对应type的sensor.

    List l = getSensorList(type);

    boolean wakeUpSensor = false;

    // For the following sensor types, return a wake-up sensor. These types are by default

    // defined as wake-up sensors. For the rest of the SDK defined sensor types return a

    // non_wake-up version.

    if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||

            type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||

            type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||

            type == Sensor.TYPE_WRIST_TILT_GESTURE || type == Sensor.TYPE_DYNAMIC_SENSOR_META) {

        wakeUpSensor = true;

    }

     

    // NO.1.2 一般sensor有一个wakeup sensor,一个non wakeup sensor

    for (Sensor sensor : l) {

        if (sensor.isWakeUpSensor() == wakeUpSensor) return sensor;

    }

    return null;

}

NO.1.1 这里是从所有的sensor中获得对应type的sensor.

public List getSensorList(int type) {

    // cache the returned lists the first time

    List list;

    // 获取所有sensor

    final List fullList = getFullSensorList();

    synchronized (mSensorListByType) {

        // 看看缓存里有没有要组成的sensor,如果有的话直接返回

        list = mSensorListByType.get(type);

        if (list == null) {

            if (type == Sensor.TYPE_ALL) {

                list = fullList;

            else {

                list = new ArrayList();

                // 遍历所有sensor,找到对应type的sensor

                for (Sensor i : fullList) {

                    if (i.getType() == type)

                        list.add(i);

                }

            }

            list = Collections.unmodifiableList(list);

            // 存入缓存

            mSensorListByType.append(type, list);

        }

    }

    return list;

}

 

// NO.1.2 一般sensor有一个wakeup sensor,一个non wakeup sensor,我们返回wakeup sensor。
若是注册Non-Wakeup的sensor的话,在系统suspend时,不会有任何数据上报.若是注册Wakeup的sensor的话,系统会被wakelock住,根本睡不下去,这时系统功耗非常高
 

NO.2注册sensor

   public boolean registerListener(SensorEventListener listener, Sensor sensor,

           int samplingPeriodUs) {

       return registerListener(listener, sensor, samplingPeriodUs, null);

   }

    

   public boolean registerListener(SensorEventListener listener, Sensor sensor,

           int samplingPeriodUs, Handler handler) {

       // SensorManager.SENSOR_DELAY_NORMAL默认采样率 200000us

       int delay = getDelay(samplingPeriodUs);

       return registerListenerImpl(listener, sensor, delay, handler, 00);

   }

@Override

   protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,

           int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {

       android.util.SeempLog.record_sensor_rate(381, sensor, delayUs);

       if (listener == null || sensor == null) {

           Log.e(TAG, "sensor or listener is null");

           return false;

       }

       // Trigger Sensors should use the requestTriggerSensor call.

       // NO2.1如果sensor类型是Sensor.REPORTING_MODE_ONE_SHOT就返回,requestTriggerSensor注册的sensor

       if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {

           Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");

           return false;

       }

       // Sensor.REPORTING_MODE_ONE_SHOT ,判断时间

       if (maxBatchReportLatencyUs < 0 || delayUs < 0) {

           Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");

           return false;

       }

       // 判断Listener数量是否超过超过MAX_LISTENER_COUNT

       if (mSensorListeners.size() >= MAX_LISTENER_COUNT) {

           throw new IllegalStateException("register failed, "

               "the sensor listeners size has exceeded the maximum limit "

               + MAX_LISTENER_COUNT);

       }

 

       // Invariants to preserve:

       // - one Looper per SensorEventListener

       // - one Looper per SensorEventQueue

       // We map SensorEventListener to a SensorEventQueue, which holds the looper

       synchronized (mSensorListeners) {

           // 从缓存里获取listener

           SensorEventQueue queue = mSensorListeners.get(listener);

           if (queue == null) {

               Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;

               final String fullClassName =

                       listener.getClass().getEnclosingClass() != null

                           ? listener.getClass().getEnclosingClass().getName()

                           : listener.getClass().getName();

               // NO2.2 新建一个SensorEventQueue

               queue = new SensorEventQueue(listener, looper, this, fullClassName);

               // NO2.3 添加sennsor

               if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {

                   queue.dispose();

                   return false;

               }

               // 将listener放入缓存

               mSensorListeners.put(listener, queue);

               return true;

           else {

               return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);

           }

       }

   }


sensor的模式类型有:
REPORTING_MODE_CONTINUOUS 常用的都是CONTINUOUS类型,例如light,acc,gryo等等
REPORTING_MODE_ON_CHANGE 
REPORTING_MODE_ONE_SHOT 例如:计步
REPORTING_MODE_SPECIAL_TRIGGER

 

NO2.2 新建一个SensorEventQueue

frameworks/base/core/java/android/hardware/SystemSensorManager.java

static final class SensorEventQueue extends BaseEventQueue {

        private final SensorEventListener mListener;

        private final SparseArray mSensorsEvents = new SparseArray();

 

        public SensorEventQueue(SensorEventListener listener, Looper looper,

                SystemSensorManager manager, String packageName) {

            // NO2.2.1调用父类方法

            super(looper, manager, OPERATING_MODE_NORMAL, packageName);

            mListener = listener;

        }

 

        @Override

        public void addSensorEvent(Sensor sensor) {

            SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,

                    mManager.mTargetSdkLevel));

            synchronized (mSensorsEvents) {

                mSensorsEvents.put(sensor.getHandle(), t);

            }

        }

        ......

        // Called from native code.

        @SuppressWarnings("unused")

        @Override

        // NO2.2.2数据分发,调用onAccuracyChanged,onSensorChanged

        protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,

                long timestamp) {

            final Sensor sensor = mManager.mHandleToSensor.get(handle);

            if (sensor == null) {

                // sensor disconnected

                return;

            }

 

            SensorEvent t = null;

            synchronized (mSensorsEvents) {

                t = mSensorsEvents.get(handle);

            }

 

            if (t == null) {

                // This may happen if the client has unregistered and there are pending events in

                // the queue waiting to be delivered. Ignore.

                return;

            }

            // Copy from the values array.

            System.arraycopy(values, 0, t.values, 0, t.values.length);

            t.timestamp = timestamp;

            t.accuracy = inAccuracy;

            t.sensor = sensor;

 

            // call onAccuracyChanged() only if the value changes

            final int accuracy = mSensorAccuracies.get(handle);

            if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {

                mSensorAccuracies.put(handle, t.accuracy);

                // 回调我们的onAccuracyChanged

                mListener.onAccuracyChanged(t.sensor, t.accuracy);

            }

            // 回调我们的onSensorChanged

            mListener.onSensorChanged(t);

        }

        ......

    }


接下来我们看看是怎么回调的

NO2.2.1调用父类方法

 

frameworks/base/core/java/android/hardware/SystemSensorManager.java

BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {

            if (packageName == null) packageName = "";

            // NO2.2.1.1初始化nativeInitBaseEventQueue

            mNativeSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,

                    new WeakReference<>(this), looper.getQueue(),

                    packageName, mode, manager.mContext.getOpPackageName());

            mCloseGuard.open("dispose");

            mManager = manager;

        }

 

NO2.2.1.1初始化nativeInitBaseEventQueue

frameworks/base/core/jni/android_hardware_SensorManager.cpp

static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,

        jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {

    SensorManager* mgr = reinterpret_cast(sensorManager);

    ScopedUtfChars packageUtf(env, packageName);

    String8 clientName(packageUtf.c_str());

    // NO2.2.1.1.2创建natvive层对应的queue

    sp queue(mgr->createEventQueue(clientName, mode));

 

    if (queue == NULL) {

        jniThrowRuntimeException(env, "Cannot construct native SensorEventQueue.");

        return 0;

    }

    //取得java层的messageQueue

    sp messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);

    if (messageQueue == NULL) {

        jniThrowRuntimeException(env, "MessageQueue is not initialized.");

        return 0;

    }

    // NO2.2.1.1.2 新建一个receiver,后边会收到消息后会通过eventQWeak回调java层的dispatchSensorEvent,eventQWeak是java层的mNativeSensorEventQueue,后边回调会用到

    sp receiver = new Receiver(queue, messageQueue, eventQWeak);

    receiver->incStrong((void*)nativeInitSensorEventQueue);

    //将receiver返回给java层

    return jlong(receiver.get());

}

 

NO2.2.1.1.2创建natvive层对应的queue

frameworks/native/libs/sensor/SensorManager.cpp

sp SensorManager::createEventQueue(String8 packageName, int mode) {

    sp queue;

 

    Mutex::Autolock _l(mLock);

    while (assertStateLocked() == NO_ERROR) {

        // 创建sensorEventConnection

        sp connection =

                mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);

        if (connection == NULL) {

            // SensorService just died or the app doesn't have required permissions.

            ALOGE("createEventQueue: connection is NULL.");

            return NULL;

        }

        queue = new SensorEventQueue(connection);

        break;

    }

    return queue;

}

 

创建sensorEventConnection

frameworks/native/services/sensorservice/SensorService.cpp

sp SensorService::createSensorEventConnection(const String8& packageName,

        int requestedMode, const String16& opPackageName) {

    // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION.

    if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {

        return NULL;

    }

 

    Mutex::Autolock _l(mLock);

    // To create a client in DATA_INJECTION mode to inject data, SensorService should already be

    // operating in DI mode.

    if (requestedMode == DATA_INJECTION) {

        if (mCurrentOperatingMode != DATA_INJECTION) return NULL;

        if (!isWhiteListedPackage(packageName)) return NULL;

    }

 

    uid_t uid = IPCThreadState::self()->getCallingUid();

    pid_t pid = IPCThreadState::self()->getCallingPid();

 

    String8 connPackageName =

            (packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName;

    String16 connOpPackageName =

            (opPackageName == String16("")) ? String16(connPackageName) : opPackageName;

    bool hasSensorAccess = mUidPolicy->isUidActive(uid);

    // 创建一个SensorEventConnection,并把它添加到mActiveConnections中

    sp result(new SensorEventConnection(this, uid, connPackageName,

            requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess));

    if (requestedMode == DATA_INJECTION) {

        if (mActiveConnections.indexOf(result) < 0) {

            mActiveConnections.add(result);

        }

        // Add the associated file descriptor to the Looper for polling whenever there is data to

        // be injected.

        result->updateLooperRegistration(mLooper);

    }

    return result;

}

 

这里思创建一个SensorEventConnection,并把它添加到mActiveConnections中,当SensorService的主线程中收到sensor事件后会遍历所有的mActiveConnections,调用它们的sendEvents方法,然后在receiver中的handleEvent会响应该事件,你可以用JAVA层的Handler来理解这个sendEvents,和handleEvent,但是它的实现和Handler不一样,这里不深入讨论了,继续receiver的代码

NO2.2.1.1.2 新建一个receiver,后边会收到消息后会通过eventQWeak回调java层的dispatchSensorEvent,eventQWeak是java层的mNativeSensorEventQueue,后边回调会用到

class Receiver : public LooperCallback {

    sp mSensorQueue;

    sp mMessageQueue;

    jobject mReceiverWeakGlobal;

    jfloatArray mFloatScratch;

    jintArray   mIntScratch;

public:

    Receiver(const sp& sensorQueue,

            const sp& messageQueue,

            jobject receiverWeak) {

        JNIEnv* env = AndroidRuntime::getJNIEnv();

        mSensorQueue = sensorQueue;

        mMessageQueue = messageQueue;

        mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);

 

        mIntScratch = (jintArray) env->NewGlobalRef(env->NewIntArray(16));

        mFloatScratch = (jfloatArray) env->NewGlobalRef(env->NewFloatArray(16));

    }

    ......

 

    virtual int handleEvent(int fd, int events, void* data) {

        JNIEnv* env = AndroidRuntime::getJNIEnv();

        sp q = reinterpret_cast(data);

        ScopedLocalRef receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));

 

        ssize_t n;

        ASensorEvent buffer[16];

        while ((n = q->read(buffer, 16)) > 0) {

            for (int i=0 ; iSetFloatArrayRegion(mFloatScratch, 01, &value);

                else if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {

                    float value[2];

                    value[0] = buffer[i].dynamic_sensor_meta.connected ? 1.f: 0.f;

                    value[1] = float(buffer[i].dynamic_sensor_meta.handle);

                    env->SetFloatArrayRegion(mFloatScratch, 02, value);

                else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {

                    env->SetIntArrayRegion(mIntScratch, 014,

                                           buffer[i].additional_info.data_int32);

                    env->SetFloatArrayRegion(mFloatScratch, 014,

                                             buffer[i].additional_info.data_float);

                else {

                    env->SetFloatArrayRegion(mFloatScratch, 016, buffer[i].data);

                }

 

                if (buffer[i].type == SENSOR_TYPE_META_DATA) {

                    // This is a flush complete sensor event. Call dispatchFlushCompleteEvent

                    // method.

                    if (receiverObj.get()) {

                        env->CallVoidMethod(receiverObj.get(),

                                            gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,

                                            buffer[i].meta_data.sensor);

                    }

                else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {

                    // This is a flush complete sensor event. Call dispatchAdditionalInfoEvent

                    // method.

                    if (receiverObj.get()) {

                        int type = buffer[i].additional_info.type;

                        int serial = buffer[i].additional_info.serial;

                        env->CallVoidMethod(receiverObj.get(),

                                            gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent,

                                            buffer[i].sensor,

                                            type, serial,

                                            mFloatScratch,

                                            mIntScratch,

                                            buffer[i].timestamp);

                    }

                }else {

                    int8_t status;

                    switch (buffer[i].type) {

                    case SENSOR_TYPE_ORIENTATION:

                    case SENSOR_TYPE_MAGNETIC_FIELD:

                    case SENSOR_TYPE_ACCELEROMETER:

                    case SENSOR_TYPE_GYROSCOPE:

                    case SENSOR_TYPE_GRAVITY:

                    case SENSOR_TYPE_LINEAR_ACCELERATION:

                        status = buffer[i].vector.status;

                        break;

                    case SENSOR_TYPE_HEART_RATE:

                        status = buffer[i].heart_rate.status;

                        break;

                    default:

                        status = SENSOR_STATUS_ACCURACY_HIGH;

                        break;

                    }

                    if (receiverObj.get()) {

                        // 回调dispatchSensorEvent

                        env->CallVoidMethod(receiverObj.get(),

                                            gBaseEventQueueClassInfo.dispatchSensorEvent,

                                            buffer[i].sensor,

                                            mFloatScratch,

                                            status,

                                            buffer[i].timestamp);

                    }

                }

                if (env->ExceptionCheck()) {

                    mSensorQueue->sendAck(buffer, n);

                    ALOGE("Exception dispatching input event.");

                    return 1;

                }

            }

            mSensorQueue->sendAck(buffer, n);

        }

        if (n<0 && n != -EAGAIN) {

            // FIXME: error receiving events, what to do in this case?

        }

        return 1;

    }

};

这里当handleEvent被调用的时候会通过前边传入的参数eventQWeak回调java层对应的BaseEventQueue,eventQWeak实际上就是java层的BaseEventQueue对象。

 

三.System_server进程

status_t SensorService::enable(const sp& connection,

        int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,

        const String16& opPackageName) {

    ......

    if (connection->addSensor(handle)) {

        // MI MOD:

        // BatteryService::enableSensor(connection->getUid(), handle);

        BatteryService::enableSensor(connection->getUid(), handle, connection->getOpPackageName());

        // the sensor was added (which means it wasn't already there)

        // so, see if this connection becomes active

        if (mActiveConnections.indexOf(connection) < 0) {

            mActiveConnections.add(connection);

        }

        ......

    return err;

}

这里enable sensor后会把connection添加到mActiveConnections中

bool SensorService::threadLoop() {

    ALOGD("nuSensorService thread starting...");

    ......

    do {

        ssize_t count = device.poll(mSensorEventBuffer, numEventMax);

        ........

 

        // Make a copy of the connection vector as some connections may be removed during the course

        // of this loop (especially when one-shot sensor events are present in the sensor_event

        // buffer). Promote all connections to StrongPointers before the lock is acquired. If the

        // destructor of the sp gets called when the lock is acquired, it may result in a deadlock

        // as ~SensorEventConnection() needs to acquire mLock again for cleanup. So copy all the

        // strongPointers to a vector before the lock is acquired.

        SortedVector< sp > activeConnections;

        // 每次循环都重新初始化mActiveConnections

        populateActiveConnections(&activeConnections);

        ........

        // Send our events to clients. Check the state of wake lock for each client and release the

        // lock if none of the clients need it.

        bool needsWakeLock = false;

        size_t numConnections = activeConnections.size();

        for (size_t i=0 ; i < numConnections; ++i) {

            if (activeConnections[i] != 0) {

                // 遍历所有的mActiveConnections, 调用sendEvents发送数据,就是前边说的handleEvent会收到数据

                activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,

                        mMapFlushEventsToConnections);

                needsWakeLock |= activeConnections[i]->needsWakeLock();

                // If the connection has one-shot sensors, it may be cleaned up after first trigger.

                // Early check for one-shot sensors.

                if (activeConnections[i]->hasOneShotSensors()) {

                    cleanupAutoDisabledSensorLocked(activeConnections[i], mSensorEventBuffer,

                            count);

                }

            }

        }

 

        if (mWakeLockAcquired && !needsWakeLock) {

            setWakeLockAcquiredLocked(false);

        }

    while (!Thread::exitPending());

 

    ALOGW("Exiting SensorService::threadLoop => aborting...");

    abort();

    return false;

}

NO2.2 新建SensorEventQueue就说完了,这里主要是创建一个SensorEvent消息队列,SensorService的主线程当收到sensor事件后会通过遍历activeConnections调用sendEvents将事件发给所有的receiver,然后会通过JNI回调对应对象的dispatchSensorEvent,最后回调onSensorChanged。接下去我们继续说NO2.3 添加sennsor

NO2.3 添加sennsor

public boolean addSensor(

            Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {

        // Check if already present.

        int handle = sensor.getHandle();

        if (mActiveSensors.get(handle)) return false;

 

        // Get ready to receive events before calling enable.

        mActiveSensors.put(handle, true);

        addSensorEvent(sensor);

        // 激活sensor

        if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {

            // Try continuous mode if batching fails.

            if (maxBatchReportLatencyUs == 0

                    || maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {

                removeSensor(sensor, false);

                return false;

            }

        }

        return true;

    }

这一步主要是往下调用,使能sensor,接下去将进入native层的nativeEnableSensor

private int enableSensor(

        Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {

    if (mNativeSensorEventQueue == 0throw new NullPointerException();

    if (sensor == nullthrow new NullPointerException();

    return nativeEnableSensor(mNativeSensorEventQueue, sensor.getHandle(), rateUs,

            maxBatchReportLatencyUs);

}

然后一步步传递会走到

frameworks/native/services/sensorservice/SensorEventConnection.cpp

status_t SensorService::SensorEventConnection::enableDisable(

        int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,

        int reservedFlags)

{

    status_t err;

#ifdef HAS_SENSOR_CONTROL

    Mutex::Autolock _l(defaultSensorControl()->mControlLock);

    updateConfigParam(enabled, handle, samplingPeriodNs, maxBatchReportLatencyNs, reservedFlags);

#endif

    // 判断是打开还是关闭

    if (enabled) {

        //打开

        err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,

                               reservedFlags, mOpPackageName);

#ifdef HAS_SENSOR_CONTROL

        if (NO_ERROR == err) {

            defaultSensorControl()->disableConnectionIfAppIsControlled(mService, this, handle);

        }

#endif

    else {

        err = mService->disable(this, handle);

    }

    return err;

}


我们跳过一些步骤直接看到SensorDevice.cpp

status_t SensorDevice::activate(void* ident, int handle, int enabled) {

    if (mSensors == nullptr) return NO_INIT;

    ......

        if (info.removeBatchParamsForIdent(ident) >= 0) {

            // 判断当前链接的个数,如果为0,说明这是第一个被APP注册的sensor

            if (info.numActiveClients() == 0) {

                // This is the last connection, we need to de-activate the underlying h/w sensor.

                actuateHardware = true;

            else {

                // Call batch for this sensor with the previously calculated best effort

                // batch_rate and timeout. One of the apps has unregistered for sensor

                // events, and the best effort batch parameters might have changed.

                ALOGD_IF(DEBUG_CONNECTIONS,

                         "\t>>> actuating h/w batch 0x%08x %" PRId64 " %" PRId64, handle,

                         info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);

                checkReturn(mSensors->batch(

                        handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch));

            }

        else {

            // sensor wasn't enabled for this ident

        }

 

        if (isClientDisabledLocked(ident)) {

            return NO_ERROR;

        }

    }

    // 当这个sensor没有被注册过,那么会继续调用activate

    if (actuateHardware) {

        ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,

                 enabled);

        // 继续往下activate

        err = StatusFromResult(checkReturn(mSensors->activate(handle, enabled)));

        ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" "disabling", handle,

                 strerror(-err));

 

        if (err != NO_ERROR && enabled) {

            // Failure when enabling the sensor. Clean up on failure.

            info.removeBatchParamsForIdent(ident);

        }

    }

 

    return err;

}


system_server进程的代码到这里就结束了,往下就是[email protected]进程的了

[email protected]进程

我们跟着时序图再跳过一些传递的步骤来到sensors_hal.cpp中的activate

int sensors_hal::activate(int handle, int enable)

{

    auto it = _sensors.find(handle);

    if (it == _sensors.end()) {

        sns_loge("handle %d not supported", handle);

        return -1;

    }

    auto& sensor = it->second;

    try {

        sns_logi("%s/%d en=%d", sensor->get_sensor_info().stringType,

                 handle, enable);

        // 判断是enable还是disable

        if (enable) {

            // NO.3

            sensor->activate();

        else {

            // NO.4

            sensor->deactivate();

        }

    catch (const exception& e) {

        sns_loge("failed: %s", e.what());

        return -1;

    }

    sns_logi("%s/%d en=%d completed", sensor->get_sensor_info().stringType,

             handle, enable);

    return 0;

}

我们继续看到NO.3调用的activate

void ssc_sensor::activate()

{

    _previous_ts = 0;

    std::memset(&_prev_sample, 0x00, sizeof(sensors_event_t));

    _activate_ts = android::elapsedRealtimeNano();

 

    std::lock_guard lk(_mutex);

    // 没有active的情况下

    if (!is_active()) {

        /* establish a new connection to ssc */

        // NO.3.1 创建一个和bp通信的连接

        _ssc_conn = make_unique(

        [this](const uint8_t *data, size_t size, uint64_t ts)

        {

            ssc_conn_event_cb(data, size, ts);

        });

        if ( _wakeup_type == SENSOR_WAKEUP)

            _ssc_conn->set_unsuspendable_channel();

        _ssc_conn->use_report_indication();

        _ssc_conn->register_error_cb([this](auto e){ this->ssc_conn_error_cb(e); });

        _ssc_conn->register_resp_cb([this](uint32_t resp_value){ ssc_conn_resp_cb(resp_value); });

 

        if(true == _is_stats_enable) {

          _ts_diff_acc = 0;

          _sample_cnt = 0;

          _max_ts_rxved = 0;

          _min_ts_rxved = MAX_UINT64;

 

          _ts_diff_acc_hal = 0;

          _max_ts_rxved_hal = 0;

          _min_ts_rxved_hal = MAX_UINT64;

 

          _ts_diff_acc_qmi = 0;

          _max_ts_rxved_qmi = 0;

          _min_ts_rxved_qmi = MAX_UINT64;

 

          _previous_ssc_ts = 0;

          _current_ssc_ts = 0;

          _ssc_ts_diff_bw_samples = 0;

          _acc_ssc_ts = 0;

          _min_ssc_ts_diff = MAX_INT64;

          _max_ssc_ts_diff = 0;

 

        }

 

        if(true == _is_ssc_latency_enable) {

          _slpi_delay_til_CM = 0;

          _slpi_sample_cnt = 0;

        }

        // 发生一些命令给BP,BP会调用重新初始化

        send_sensor_config_request();

    }

}

NO.3.1 创建一个和bp通信的连接,省略一些步骤直接看到qmi通信的核心文件qmi_cci_xport_qrtr.c

vendor/qcom/proprietary/commonsys-intf/qmi-framework/qcci/src/qmi_cci_xport_qrtr.c

static void *xport_open

(

 void *xport_data,

 qmi_cci_client_type *clnt,

 uint32_t service_id,

 uint32_t version,

 void *addr,

 uint32_t max_rx_len

 )

{

  struct xport_handle *xp = calloc(sizeof(struct xport_handle), 1);

  int sk_size = INT_MAX;

  int align_size = 0;

  int flags;

 

  if (!xp)

  {

    QMI_FW_LOGE("%s: xp calloc failed\n", __func__);

    return NULL;

  }

 

  xp->clnt = clnt;

  xp->srv_name.service = service_id;

  xp->srv_name.instance = version;

  xp->max_rx_len = (max_rx_len + QMI_HEADER_SIZE);

  align_size = ALIGN_SIZE(xp->max_rx_len);

  xp->max_rx_len += align_size;

  LINK_INIT(xp->link);

 

  pthread_mutex_lock(&ctrl_port_init_lock);

  if (qmi_cci_xport_ctrl_port_init() < 0) {

      pthread_mutex_unlock(&ctrl_port_init_lock);

      goto xport_open_free_xp;

  }

  pthread_mutex_unlock(&ctrl_port_init_lock);

 

  if (!addr)

    /* No need to create data port as this is a notifier port. */

    goto xport_open_success;

  // 创建一个新的socket

  xp->fd = socket(AF_QIPCRTR, SOCK_DGRAM, 0);

  if(xp->fd < 0)

  {

    QMI_FW_LOGE("%s: socket creation failed - %d\n", __func__, errno);

    goto xport_open_free_xp;

  }

 

  if(fcntl(xp->fd, F_SETFD, FD_CLOEXEC) < 0)

  {

    QMI_FW_LOGE("%s: Close on exec can't be set on fd - %d\n",

        __func__, errno);

    goto xport_open_close_fd;

  }

  setsockopt(xp->fd, SOL_SOCKET, SO_RCVBUF, (char *)&sk_size, sizeof(sk_size));

  // NO.3.2 创建一个data_msg_reader_thread去接收BP发上来的数据

  if (reader_thread_data_init(&xp->rdr_tdata, (void *)xp,

      data_msg_reader_thread) < 0)

    goto xport_open_close_fd;

  memcpy(xp->svc_addr, addr, sizeof(struct xport_ipc_router_server_addr));

  xp->is_client = 1;

  flags = fcntl(xp->fd, F_GETFL, 0);

  fcntl(xp->fd, F_SETFL, flags | O_NONBLOCK);

  if(write(xp->rdr_tdata.wakeup_pipe[1], "a"1) < 0)

    QMI_FW_LOGE("%s: Error writing to pipe\n", __func__);

  QMI_CCI_LOGD("xport_open[%d]: max_rx_len=%d\n", xp->fd, max_rx_len);

 

xport_open_success:

  LOCK(&ctrl_port->xport_list_lock);

  LIST_ADD(ctrl_port->xport, xp, link);

  UNLOCK(&ctrl_port->xport_list_lock);

  return xp;

xport_open_close_fd:

  close(xp->fd);

xport_open_free_xp:

  free(xp);

  return NULL;

}

NO.3.2 创建一个data_msg_reader_thread去接收BP发上来的数据

static void *data_msg_reader_thread(void *arg)

{

  struct xport_handle *xp = (struct xport_handle *)arg;

  unsigned char ch, *buf;

  int i;

  ssize_t rx_len;

  struct pollfd pbits[2];

  struct xport_ipc_router_server_addr src_addr;

  struct sockaddr_qrtr addr;

 

  while(1)

  {

    pbits[0].fd = xp->rdr_tdata.wakeup_pipe[0];

    pbits[0].events = POLLIN;

    pbits[1].fd = xp->fd;

    pbits[1].events = POLLIN;

 

    i = poll(pbits, 2, -1);

    ......

 

      QMI_CCI_LOGD("%s: Received %d bytes from %d\n", __func__, rx_len, xp->fd);

      src_addr.service = 0;

      src_addr.instance = 0;

      src_addr.node_id = addr.sq_node;

      src_addr.port_id = addr.sq_port;

      qmi_cci_xport_recv(xp->clnt, (void *)&src_addr, buf, (uint32_t)rx_len);

      free(buf);

    }

    ......

}


当这里读到数据之后就要开始分发了,将在下一文章中说

五.调试技巧及关键点

      看了这么多可能还是是懂非懂的话,可以亲自动手来调试一下,调试的关键点我都已经帮你准备好了,你只需要准备好gdb就可以动手调试了吗,如果gdb你不会用的话,后续我会给你更新一个gdb脚本,运行脚本就能直接attach上对应的进程了

1.APP进程完整调用栈
①gdb断点system_server端:b frameworks/native/libs/sensor/ISensorEventConnection.cpp:138,并继续运行
②打开写好的sensor APP
③当gdb停下时,打印APP的调用栈(kill -3)

app端调用栈如下:
"main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x790aa3c8 self=0x72e0814c00
| sysTid=7143 nice=-10 cgrp=default sched=0/0 handle=0x7366679548
| state=S schedstat=( 188550465 7333019 193 ) utm=15 stm=2 core=7 HZ=100
| stack=0x7fce674000-0x7fce676000 stackSize=8MB
| held mutexes=
kernel: (couldn't read /proc/self/task/7143/stack)
native: #00 pc 000000000007aec4 /system/lib64/libc.so (__ioctl+4)
native: #01 pc 000000000002ad80 /system/lib64/libc.so (ioctl+132)
native: #02 pc 000000000005d0b0 /system/lib64/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+244)
native: #03 pc 000000000005de5c /system/lib64/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+60)
native: #04 pc 000000000005dcb0 /system/lib64/libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+176)
native: #05 pc 0000000000051a18 /system/lib64/libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+72)
native: #06 pc 000000000000daec /system/lib64/libsensor.so (android::BpSensorEventConnection::enableDisable(int, bool, long, long, int)+184)
native: #07 pc 000000000018eb0c /system/lib64/libandroid_runtime.so ((anonymous namespace)::nativeEnableSensor(_JNIEnv*, _jclass*, long, int, int, int)+116)
at android.hardware.SystemSensorManager$BaseEventQueue.nativeEnableSensor(Native method)
at android.hardware.SystemSensorManager$BaseEventQueue.enableSensor(SystemSensorManager.java:748)
at android.hardware.SystemSensorManager$BaseEventQueue.addSensor(SystemSensorManager.java:673)
at android.hardware.SystemSensorManager.registerListenerImpl(SystemSensorManager.java:179)
- locked <0x07ed7b61> (a java.util.HashMap)
at android.hardware.SensorManager.registerListener(SensorManager.java:821)
at android.hardware.SensorManager.registerListener(SensorManager.java:728)
at com.example.mi.sensortest.MainActivity.onResume(MainActivity.java:42)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1413)
at android.app.Activity.performResume(Activity.java:7408)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3862)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3902)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1846)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6882)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)

 

2.system_server进程完整调用栈
①gdb断点[email protected]进程:b vendor/qcom/proprietary/commonsys-intf/qmi-framework/qcci/src/qmi_cci_xport_qrtr.c:621,并继续运行
②打开写好的sensor APP
③当gdb停下时,打印system_server的调用栈(kill -3)
调用栈如下:

"Binder:24480_2" prio=5 tid=9 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x135403c0 self=0x7da5416400
| sysTid=24494 nice=0 cgrp=default sched=0/0 handle=0x7d8a50e4f0
| state=S schedstat=( 313473857 56524414 2439 ) utm=20 stm=10 core=2 HZ=100
| stack=0x7d8a413000-0x7d8a415000 stackSize=1009KB
| held mutexes=
kernel: (couldn't read /proc/self/task/24494/stack)
native: #00 pc 000000000007aec4 /system/lib64/libc.so (__ioctl+4)
native: #01 pc 000000000002ad80 /system/lib64/libc.so (ioctl+132)
native: #02 pc 000000000001e9cc /system/lib64/libhwbinder.so (android::hardware::IPCThreadState::talkWithDriver(bool)+200)
native: #03 pc 000000000001f5d0 /system/lib64/libhwbinder.so (android::hardware::IPCThreadState::waitForResponse(android::hardware::Parcel*, int*)+60)
native: #04 pc 000000000001ba48 /system/lib64/libhwbinder.so (android::hardware::BpHwBinder::transact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function)+132)
native: #05 pc 000000000000de38 /system/lib64/[email protected] (android::hardware::sensors::V1_0::BpHwSensors::_hidl_activate(android::hardware::IInterface*, android::hardware::details::HidlInstrumentor*, int, bool)+236)
native: #06 pc 0000000000018410 /system/lib64/libsensorservice.so (android::SensorDevice::activate(void*, int, int)+852)
native: #07 pc 000000000002ccc4 /system/lib64/libsensorservice.so (android::SensorService::enable(android::sp const&, int, long, long, int, android::String16 const&)+2400)
native: #08 pc 0000000000020790 /system/lib64/libsensorservice.so (android::SensorService::SensorEventConnection::enableDisable(int, bool, long, long, int)+216)
native: #09 pc 000000000000d8e8 /system/lib64/libsensor.so (android::BnSensorEventConnection::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+428)
native: #10 pc 000000000004fc6c /system/lib64/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+136)
native: #11 pc 000000000005d5cc /system/lib64/libbinder.so (android::IPCThreadState::executeCommand(int)+520)
native: #12 pc 000000000005d310 /system/lib64/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+156)
native: #13 pc 000000000005da00 /system/lib64/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+108)
native: #14 pc 000000000007feec /system/lib64/libbinder.so (android::PoolThread::threadLoop()+24)
native: #15 pc 00000000000100dc /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+284)
native: #16 pc 00000000000b6bbc /system/lib64/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+140)
native: #17 pc 00000000000904b8 /system/lib64/libc.so (__pthread_start(void*)+36)
native: #18 pc 0000000000023c38 /system/lib64/libc.so (__start_thread+68)
Stack Trace:
RELADDR FUNCTION FILE:LINE
000000000007aec4 __ioctl+4 /proc/self/cwd/bionic/libc/arch-arm64/syscalls/__ioctl.S:7
000000000002ad80 ioctl+132 bionic/libc/bionic/ioctl.cpp:39
000000000001e9cc android::hardware::IPCThreadState::talkWithDriver(bool)+200 system/libhwbinder/IPCThreadState.cpp:927
000000000001f5d0 android::hardware::IPCThreadState::waitForResponse(android::hardware::Parcel*, int*)+60 system/libhwbinder/IPCThreadState.cpp:790
000000000001ba48 android::hardware::BpHwBinder::transact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function)+132 system/libhwbinder/IPCThreadState.cpp:?
000000000000de38 android::hardware::sensors::V1_0::BpHwSensors::_hidl_activate(android::hardware::IInterface*, android::hardware::details::HidlInstrumentor*, int, bool)+236 out/soong/.intermediates/hardware/interfaces/sensors/1.0/[email protected]_genc++/gen/android/hardware/sensors/1.0/SensorsAll.cpp:307
0000000000018410 android::SensorDevice::activate(void*, int, int)+852 frameworks/native/services/sensorservice/SensorDevice.cpp:303
000000000002ccc4 android::SensorService::enable(android::sp const&, int, long, long, int, android::String16 const&)+2400 frameworks/native/services/sensorservice/SensorService.cpp:1507
0000000000020790 android::SensorService::SensorEventConnection::enableDisable(int, bool, long, long, int)+216 frameworks/native/services/sensorservice/SensorEventConnection.cpp:580
000000000000d8e8 android::BnSensorEventConnection::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+428 frameworks/native/libs/sensor/ISensorEventConnection.cpp:138
000000000004fc6c android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+136 frameworks/native/libs/binder/Binder.cpp:129
000000000005d5cc android::IPCThreadState::executeCommand(int)+520 frameworks/native/libs/binder/IPCThreadState.cpp:1121
000000000005d310 android::IPCThreadState::getAndExecuteCommand()+156 frameworks/native/libs/binder/IPCThreadState.cpp:458
000000000005da00 android::IPCThreadState::joinThreadPool(bool)+108 frameworks/native/libs/binder/IPCThreadState.cpp:538
000000000007feec android::PoolThread::threadLoop()+24 frameworks/native/libs/binder/ProcessState.cpp:61
00000000000100dc android::Thread::_threadLoop(void*)+284 system/core/libutils/Threads.cpp:744
00000000000b6bbc android::AndroidRuntime::javaThreadShell(void*)+140 frameworks/base/core/jni/AndroidRuntime.cpp:1309
00000000000904b8 __pthread_start(void*)+36 bionic/libc/bionic/pthread_create.cpp:254
0000000000023c38 __start_thread+68 bionic/libc/bionic/clone.cpp:52

 

[email protected]进程完整调用栈
①gdb断点[email protected]进程:b vendor/qcom/proprietary/commonsys-intf/qmi-framework/qcci/src/qmi_cci_xport_qrtr.c:621,并继续运行
②打开写好的sensor APP
③当gdb停下时,bt打印调用栈

(gdb) bt
#0  xport_open (xport_data=0x0 <_DYNAMIC>, clnt=0x7737246800, service_id=400, version=1, addr=0x0 <_DYNAMIC>, max_rx_len=0)
    at vendor/qcom/proprietary/commonsys-intf/qmi-framework/qcci/src/qmi_cci_xport_qrtr.c:629
#1  0x0000007736589bf0 in qmi_client_notifier_init (service_obj=, os_params=0x7ffd1b2928, user_handle=0x7ffd1b2908)
    at vendor/qcom/proprietary/commonsys-intf/qmi-framework/qcci/src/qmi_cci_common.c:1619
#2  0x0000007736b031d8 in ssc_qmi_connection::qmi_wait_for_service (this=0x77372a2c00) at vendor/qcom/proprietary/commonsys-intf/sensors-see/ssc/ssc_connection.cpp:242
#3  0x0000007736b02788 in ssc_qmi_connection::qmi_connect (this=0x77372a2c00) at vendor/qcom/proprietary/commonsys-intf/sensors-see/ssc/ssc_connection.cpp:303
#4  0x0000007736b02dd0 in ssc_qmi_connection::ssc_qmi_connection(std::__1::function) (this=0x77372a2c00, event_cb=...)
    at vendor/qcom/proprietary/commonsys-intf/sensors-see/ssc/ssc_connection.cpp:214
#5  0x0000007736b0583c in std::__1::make_unique&>(std::__1::function&) (__args=...) at external/libcxx/include/memory:3126
#6  ssc_connection::ssc_connection(std::__1::function) (this=0x773722b0c0, event_cb=...)
    at vendor/qcom/proprietary/commonsys-intf/sensors-see/ssc/ssc_connection.cpp:814
#7  0x00000077366f7a10 in std::__1::make_unique(ssc_sensor::activate()::$_1&&) (__args=) at external/libcxx/include/memory:3126
#8  ssc_sensor::activate (this=0x77362c6f00) at vendor/qcom/proprietary/sensors-see/sensors-hal/framework/ssc_sensor.cpp:168
#9  0x00000077366f0a2c in sensors_hal::activate (this=, handle=46, enable=1) at vendor/qcom/proprietary/sensors-see/sensors-hal/framework/sensors_hal.cpp:109
#10 0x000000773708bd28 in android::hardware::sensors::V1_0::implementation::Sensors::activate (this=0x0 <_DYNAMIC>, sensor_handle=925132800, enabled=)
    at hardware/interfaces/sensors/1.0/default/Sensors.cpp:154
#11 0x00000077378d0efc in android::hardware::sensors::V1_0::BnHwSensors::_hidl_activate(android::hidl::base::V1_0::BnHwBase*, android::hardware::Parcel const&, android::hardware::Parcel*, std::__1::function) (_hidl_this=0x7737241140, _hidl_data=..., _hidl_reply=, _hidl_cb=...)
    at out/soong/.intermediates/hardware/interfaces/sensors/1.0/[email protected]_genc++/gen/android/hardware/sensors/1.0/SensorsAll.cpp:1193
#12 0x00000077378d20d8 in android::hardware::sensors::V1_0::BnHwSensors::onTransact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function) (this=, _hidl_code=, _hidl_data=..., _hidl_reply=, _hidl_flags=, _hidl_cb=...)
    at out/soong/.intermediates/hardware/interfaces/sensors/1.0/[email protected]_genc++/gen/android/hardware/sensors/1.0/SensorsAll.cpp:1770
#13 0x0000007737cdd918 in android::hardware::BHwBinder::transact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function) (this=0x0 <_DYNAMIC>, code=925132800, data=..., reply=0x1 <_DYNAMIC+1>, flags=0, callback=...) at system/libhwbinder/Binder.cpp:116
#14 0x0000007737ce0f24 in android::hardware::IPCThreadState::executeCommand (this=, cmd=) at system/libhwbinder/IPCThreadState.cpp:1178
#15 0x0000007737ce0b68 in android::hardware::IPCThreadState::getAndExecuteCommand (this=0x7737246000) at system/libhwbinder/IPCThreadState.cpp:461
#16 0x0000007737cd5700 in android::hardware::IPCThreadState::joinThreadPool (this=0x7737246000, isMain=true) at system/libhwbinder/IPCThreadState.cpp:551
#17 0x0000005afdb1ead8 in android::hardware::defaultPassthroughServiceImplementation (name=..., maxThreads=)
    at system/libhidl/transport/include/hidl/LegacySupport.h:76
#18 android::hardware::defaultPassthroughServiceImplementation (maxThreads=) at system/libhidl/transport/include/hidl/LegacySupport.h:82
#19 0x0000007737a2990c in __libc_init (raw_args=, onexit=, slingshot=, structors=) at bionic/libc/bionic/libc_init_dynamic.cpp:129

你可能感兴趣的:(安卓系统)