3:SensorManager

上一部分说过,开机后,system server启动时,就会初始化sensor service,也就是说,开机后她一直都在后台运行着,客户端部分,直接connect就行了。至于怎么connect,这一切都被封装到SensorManager里了。

3.1 SensorManager的创建

获取SensorManager的对象实例代码:

mSensorManager =(SensorManager)getSystemService(SENSOR_SERVICE);

调用Activity的成员函数来获取SensorManager实例,我们从Activity派生关系可以追溯到,这个函数的最终在ContextImpl实现:

[java] view plaincopy
  1. //ContextImpl.java
  2. @Override
  3. public ObjectgetSystemService(String name) {
  4. ServiceFetcherfetcher = SYSTEM_SERVICE_MAP.get(name);
  5. return fetcher ==null ? null : fetcher.getService(this);
  6. }

这个函数从SYSTEM_SERVICE_MAP中获取了name对应的特定对象实例,所以从SYSTEM_SERVICE_MAP的初始化,就可以看到SensorManager对象的创建:

[java] view plaincopy
  1. //ContextImpl.java
  2. static{     ...
  3. registerService(SENSOR_SERVICE, newServiceFetcher() {
  4. public ObjectcreateService(ContextImpl ctx) {
  5. return newSensorManager(ctx.mMainThread.getHandler().getLooper());
  6. }}); ...
  7. }

3.2 初始化并连接sensor service

初始化过程肯定是在构造函数中进行,那如何连接sensor service呢?上一部分说过,sensor service是基于c++代码编写的native binder,客户端要与其连接并交互,当然也是使用c++更方便(我只是说比较方便,当然你如果硬要用java与其建立连接并交互数据,也是可以的).

如果一种做法可以让你更方便,我想大多数人的选择都是一样的,就是使用C++代码访问服务,然后java代码通过jni调用c++代码,这也是android系统的通用做法;接下去,我们看下SensorManager的jni函数映射:

在android jni中c++类文件的命名规则一般都是java类的package路径+类名,还有一点需要注意的是,这里jni映射函数名都是一样的,这只是这个类的设计者这么命名而已,实际上c++类中的对应函数命名是没有限制的,关于jni的详细描述,大家可查看相关资料,这里就不再赘述.

在了解了jni函数映射后,后续在java代码中如果调用了native函数,我们将直接跳转到c++代码.

SensorManager被实例化,地球人都知道构造函数先走,所以接下去看SensorManager构造函数:

[java] view plaincopy
  1. public SensorManager(Looper mainLooper) {
  2. mMainLooper = mainLooper;
  3. synchronized(sListeners) {
  4. if (!sSensorModuleInitialized) {
  5. sSensorModuleInitialized =true;
  6. nativeClassInit();
  7. sWindowManager =IWindowManager.Stub.asInterface(
  8. ServiceManager.getService("window"));
  9. if (sWindowManager != null) {
  10. // if it's null we'rerunning in the system process
  11. // which won't get therotated values
  12. try {
  13. sRotation =sWindowManager.watchRotation(
  14. newIRotationWatcher.Stub() {
  15. public voidonRotationChanged(int rotation) {
  16. SensorManager.this.onRotationChanged(rotation);
  17. }
  18. }
  19. );
  20. } catch (RemoteException e){
  21. }
  22. }
  23. // initialize the sensor list
  24. sensors_module_init();
  25. final ArrayList<Sensor>fullList = sFullSensorsList;
  26. int i = 0;
  27. do {
  28. Sensor sensor = newSensor();
  29. i =sensors_module_get_next_sensor(sensor, i);
  30. if (i>=0) {
  31. //Log.d(TAG,"found sensor: " + sensor.getName() +
  32. //        ", handle=" + sensor.getHandle());
  33. sensor.setLegacyType(getLegacySensorType(sensor.getType()));
  34. fullList.add(sensor);
  35. sHandleToSensor.append(sensor.getHandle(), sensor);
  36. }
  37. } while (i>0);
  38. sPool = new SensorEventPool(sFullSensorsList.size()*2 );
  39. sSensorThread = newSensorThread();
  40. }
  41. }
  42. }

先调用nativeClassInit来初始化JNI相关java类信息,对应C++代码:

[java] view plaincopy
  1. static void
  2. nativeClassInit(JNIEnv *_env, jclass _this)
  3. {
  4. jclass sensorClass =_env->FindClass("android/hardware/Sensor");
  5. SensorOffsets& sensorOffsets =gSensorOffsets;
  6. sensorOffsets.name        = _env->GetFieldID(sensorClass,"mName",      "Ljava/lang/String;");
  7. sensorOffsets.vendor      = _env->GetFieldID(sensorClass,"mVendor",   "Ljava/lang/String;");
  8. sensorOffsets.version     = _env->GetFieldID(sensorClass,"mVersion",   "I");
  9. sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
  10. sensorOffsets.type        = _env->GetFieldID(sensorClass,"mType",      "I");
  11. sensorOffsets.range       = _env->GetFieldID(sensorClass,"mMaxRange",  "F");
  12. sensorOffsets.resolution  = _env->GetFieldID(sensorClass,"mResolution","F");
  13. sensorOffsets.power       = _env->GetFieldID(sensorClass,"mPower",     "F");
  14. sensorOffsets.minDelay    = _env->GetFieldID(sensorClass,"mMinDelay",  "I");
  15. }

从代码上看出,这个函数主要是保存java类Sensor的各个filed的id值,方便后续在c++代码中利用Jni环境向jave层传递数据,这个在后续poll sensor值的时候会用到。接着调用jni函数sensors_module_init,c++代码如下:

[java] view plaincopy
  1. static jint
  2. sensors_module_init(JNIEnv*env, jclass clazz)
  3. {
  4. SensorManager::getInstance();
  5. return 0;
  6. }

函数很简单,就调用SensorManager::getInstance实例化SensorManager对象实例。注意这里是jnic++层的实现,SensorManager对象是C++层的对象实例,不要跟上面java层的搞浑了。getInstance,可以明显看出来,这是一个单例对象,继续看c++ SensorManager的构造函数:

[java] view plaincopy
  1. SensorManager::SensorManager()
  2. : mSensorList(0)
  3. {
  4. // okay we're not locked here, but it's notneeded during construction
  5. assertStateLocked();
  6. }

构造函数就调了assertStateLocked,继续看这个函数:

[java] view plaincopy
  1. status_tSensorManager::assertStateLocked() const {
  2. if (mSensorServer == NULL) {
  3. // try for one second
  4. const String16name("sensorservice");  //定义sensorservie服务端名字匹配
  5. for (int i=0 ; i<4 ; i++) {
  6. //打通SensorManager.cpp和SensorService.cpp
  7. status_t err = getService(name,&mSensorServer) 
  8. if (err == NAME_NOT_FOUND) {
  9. usleep(250000);
  10. continue;
  11. }
  12. if (err != NO_ERROR) {
  13. return err;
  14. }
  15. break;
  16. }
  17. class DeathObserver : publicIBinder::DeathRecipient {
  18. SensorManager& mSensorManger;
  19. virtual void binderDied(constwp<IBinder>& who) {
  20. LOGW("sensorservice died[%p]", who.unsafe_get());
  21. mSensorManger.sensorManagerDied();
  22. }
  23. public:
  24. DeathObserver(SensorManager&mgr) : mSensorManger(mgr) { }
  25. };
  26. mDeathObserver = newDeathObserver(*const_cast<SensorManager *>(this));
  27. mSensorServer->asBinder()->linkToDeath(mDeathObserver);
  28. mSensors =mSensorServer->getSensorList();
  29. size_t count = mSensors.size();
  30. mSensorList = (Sensorconst**)malloc(count * sizeof(Sensor*));
  31. for (size_t i=0 ; i<count ; i++) {
  32. mSensorList[i] = mSensors.array() +i;
  33. }
  34. }
  35. return NO_ERROR;
  36. }

这个函数通过getService拿到sensorservice的proxy binder,这样就建立了与sensorservice的数据连接,然后调用getsensorlist从sensorservice获取sensor list并保存。

ok,到这里,java层的jni函数sensors_module_init()就走完了,我们已经与sensor service建立连接,并已经取得了sensor list,但是这些数据目前是存于c++层的,我们要通过jni将数据拿到java层,所以在java层SensorManager构造函数调用sensors_module_init()后,调用sensors_module_get_next_sensor获取sensor数据并保存。

下面是jni函数sensors_module_get_next_sensor的c++实现:

[java] view plaincopy
  1. //android_hardware_SensorManager.cpp
  2. static jint
  3. sensors_module_get_next_sensor(JNIEnv*env, jobject clazz, jobject sensor, jint next)
  4. {
  5. SensorManager&mgr(SensorManager::getInstance());
  6. Sensor const* const* sensorList;
  7. size_t count =mgr.getSensorList(&sensorList);
  8. if (size_t(next) >= count)
  9. return -1;
  10. Sensor const* const list =sensorList[next];
  11. const SensorOffsets&sensorOffsets(gSensorOffsets);
  12. jstring name =env->NewStringUTF(list->getName().string());
  13. jstring vendor =env->NewStringUTF(list->getVendor().string());
  14. env->SetObjectField(sensor,sensorOffsets.name,      name);
  15. env->SetObjectField(sensor,sensorOffsets.vendor,    vendor);
  16. env->SetIntField(sensor,sensorOffsets.version,      1);
  17. env->SetIntField(sensor,sensorOffsets.handle,       list->getHandle());
  18. env->SetIntField(sensor,sensorOffsets.type,        list->getType());
  19. env->SetFloatField(sensor,sensorOffsets.range,     list->getMaxValue());
  20. env->SetFloatField(sensor,sensorOffsets.resolution, list->getResolution());
  21. env->SetFloatField(sensor,sensorOffsets.power,     list->getPowerUsage());
  22. env->SetIntField(sensor,sensorOffsets.minDelay,    list->getMinDelay());
  23. next++;
  24. return size_t(next) < count ? next : 0;
  25. }

在这个函数将对应的c++层保存的sensor数据传给jobjectsensor。

java层SensorManager构造函数最后创建SensorEventPool和sSensorThread, 这两个对象干嘛用的?看名字就知道啦,一个是事件池,sensor 事件很频繁,如果对每一个事件都创建一个新对象,开销太大,弄一个事件池肯定是最好的选择;另外一个是sensor 线程,负责读取sensor 数据.

3.3 sensor数据读取

继续来看下应用层获取sensor数据的代码:

[java] view plaincopy
  1. public classSensorActivity extends Activity, implements SensorEventListener {
  2. private final SensorManagermSensorManager;
  3. private final Sensor mAccelerometer;
  4. public SensorActivity() {
  5. //获取对应服务
  6. mSensorManager =(SensorManager)getSystemService(SENSOR_SERVICE);
  7. //获取指定sensor对象
  8. mAccelerometer =mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  9. }
  10. protected void onResume() {
  11. super.onResume();
  12. //注册listener用于数据回调
  13. mSensorManager.registerListener(this,mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
  14. }
  15. protected void onPause() {
  16. super.onPause();
  17. mSensorManager.unregisterListener(this);
  18. }
  19. public void onAccuracyChanged(Sensorsensor, int accuracy) {
  20. }
  21. public void onSensorChanged(SensorEventevent) {
  22. }
  23. }

现在看这代码就很清楚了

1:(SensorManager)getSystemService(SENSOR_SERVICE)获取SensorManager对象,做了我们上面所介绍的初始化工作

2:mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),获取指定sensor对象,根据初始化获取的Sensor List。

3:mSensorManager.registerListener(this,mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);注册listener获取sensor数据

还记得上一部分说的sensor client与sensor service建立active connection来传递数据吗?service端创建connection是由client端也就是由应用端发起的; 上面1,2都是初始化工作,那真正发起的代码,肯定就是registerlistener了,下面根据代码详细分析:

[java] view plaincopy
  1. public booleanregisterListener(SensorEventListener listener, Sensor sensor, int rate) {
  2. return registerListener(listener,sensor, rate, null);
  3. }

直接调用重载函数

[java] view plaincopy
  1. public booleanregisterListener(SensorEventListener listener, Sensor sensor, int rate,
  2. Handler handler) {
  3. if (listener == null || sensor == null){
  4. return false;
  5. }
  6. boolean result = true;
  7. int delay = -1;
  8. switch (rate) {
  9. case SENSOR_DELAY_FASTEST:
  10. delay = 0;
  11. break;
  12. case SENSOR_DELAY_GAME:
  13. delay = 20000;
  14. break;
  15. case SENSOR_DELAY_UI:
  16. delay = 66667;
  17. break;
  18. case SENSOR_DELAY_NORMAL:
  19. delay = 200000;
  20. break;
  21. default:
  22. delay = rate;
  23. break;
  24. }
  25. synchronized (sListeners) {
  26. // look for this listener in our list
  27. ListenerDelegate l = null;
  28. for (ListenerDelegate i :sListeners) {
  29. if (i.getListener() ==listener) {
  30. l = i;
  31. break;
  32. }
  33. }
  34. // if we don't find it, add it tothe list
  35. if (l == null) {
  36. l = newListenerDelegate(listener, sensor, handler);
  37. sListeners.add(l);
  38. // if the list is not empty,start our main thread
  39. if (!sListeners.isEmpty()) {
  40. if(sSensorThread.startLocked()) {
  41. if(!enableSensorLocked(sensor, delay)) {
  42. // oops. there was an error
  43. sListeners.remove(l);
  44. result = false;
  45. }
  46. } else {
  47. // there was an error,remove the listener
  48. sListeners.remove(l);
  49. result = false;
  50. }
  51. } else {
  52. // weird, we couldn't addthe listener
  53. result = false;
  54. }
  55. } else {
  56. l.addSensor(sensor);
  57. if (!enableSensorLocked(sensor,delay)) {
  58. // oops. there was an error
  59. l.removeSensor(sensor);
  60. result = false;
  61. }
  62. }
  63. }
  64. return result;

这个函数使用出现了两个新的变量,分别是sListeners和sSensorThread,对应的类型分别是ListenerDelegate和SensorThread,ListenerDelegate主要是对SensorEventListener做封装,从而使一个listener可以对应多个sensor,SensorThread则负责从sensor service读取sensor数据;该函数先判断lstener对应的ListenerDelegate是否已经创建,如果未创建,新建并将其添加入sListeners,然后查看Sensor Thread是否已经启动,如果没有启动,调用sSensorThread.startLocked()启动线程,接下去调用enableSensorLocked到service端enable对应的sensor.

先来看startlocked:

[java] view plaincopy
  1. boolean startLocked() {
  2. try {
  3. if (mThread == null) {
  4. mSensorsReady = false;
  5. SensorThreadRunnablerunnable = new SensorThreadRunnable();
  6. Thread thread = newThread(runnable, SensorThread.class.getName());
  7. thread.start();
  8. synchronized (runnable) {
  9. while (mSensorsReady ==false) {
  10. runnable.wait();
  11. }
  12. }
  13. mThread = thread;
  14. }
  15. } catch (InterruptedException e) {
  16. }
  17. return mThread == null ? false :true;
  18. }

如果线程未创建,创建SensorThreadRunnable,然后初始化线程并启动,线程启动后SensorThreadRunnable.run会被执行:

[java] view plaincopy
  1. private class SensorThreadRunnable implementsRunnable {
  2. SensorThreadRunnable() {
  3. }
  4. private boolean open() {
  5. // NOTE: this cannotsynchronize on sListeners, since
  6. // it's held in the main threadat least until we
  7. // return from here.
  8. sQueue = sensors_create_queue();
  9. return true;
  10. }
  11. public void run() {
  12. //Log.d(TAG, "enteringmain sensor thread");
  13. final float[] values = newfloat[3];
  14. final int[] status = newint[1];
  15. final long timestamp[] = newlong[1];
  16. Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
  17. if (!open()) {
  18. return;
  19. }
  20. synchronized (this) {
  21. // we've open the driver,we're ready to open the sensors
  22. mSensorsReady = true;
  23. this.notify();
  24. }
  25. while (true) {
  26. // wait for an event
  27. final int sensor =sensors_data_poll(sQueue, values, status, timestamp);
  28. int accuracy = status[0];
  29. synchronized (sListeners) {
  30. if (sensor == -1 ||sListeners.isEmpty()) {
  31. // we lost theconnection to the event stream. this happens
  32. // when the lastlistener is removed or if there is an error
  33. if (sensor == -1&& !sListeners.isEmpty()) {
  34. // log awarning in case of abnormal termination
  35. Log.e(TAG,"_sensors_data_poll() failed, we bail out: sensors=" + sensor);
  36. }
  37. // we have no morelisteners or polling failed, terminate the thread
  38. sensors_destroy_queue(sQueue);
  39. sQueue = 0;
  40. mThread = null;
  41. break;
  42. }
  43. final SensorsensorObject = sHandleToSensor.get(sensor);
  44. if (sensorObject !=null) {
  45. // report thesensor event to all listeners that
  46. // care about it.
  47. final int size =sListeners.size();
  48. for (int i=0 ;i<size ; i++) {
  49. ListenerDelegate listener = sListeners.get(i);
  50. if(listener.hasSensor(sensorObject)) {
  51. // this isasynchronous (okay to call
  52. // withsListeners lock held).
  53. listener.onSensorChangedLocked(sensorObject,
  54. values, timestamp, accuracy);
  55. }
  56. }
  57. }
  58. }
  59. }
  60. //Log.d(TAG, "exiting mainsensor thread");
  61. }
  62. }
  63. }

run执行时,先调用open,open函数很简单,就调用sensors_create_queue()来创建数据队列,显然这个队列是用于sensor数据传输的,sensors_create_queue()是jni函数,接下去看其对应c++部分代码:

[cpp] view plaincopy
  1. staticjint
  2. sensors_create_queue(JNIEnv*env, jclass clazz)
  3. {
  4. SensorManager&mgr(SensorManager::getInstance());
  5. sp<SensorEventQueue>queue(mgr.createEventQueue());
  6. queue->incStrong(clazz);
  7. returnreinterpret_cast<int>(queue.get());
  8. }

调用SensorManager.createEventQueue来创建队列:

[cpp] view plaincopy
  1. sp<SensorEventQueue>SensorManager::createEventQueue()
  2. {
  3. sp<SensorEventQueue> queue;
  4. Mutex::Autolock _l(mLock);
  5. while(assertStateLocked() == NO_ERROR) {
  6. sp<ISensorEventConnection>connection =
  7. mSensorServer->createSensorEventConnection();
  8. if (connection == NULL) {
  9. // SensorService just died.
  10. LOGE("createEventQueue:connection is NULL. SensorService died.");
  11. continue;
  12. }
  13. queue = newSensorEventQueue(connection);
  14. break;
  15. }
  16. return queue;
  17. }

调用mSensorServer->createSensorEventConnection()与server端建立连接,接着将获取的connection对象创建SensorEventQueue对象并返回。

sensors_create_queue函数接着调用queue.get()获取队列的指针,并返回给java层

回过头来继续看java调用sensors_create_queue的open函数:

[java] view plaincopy
  1. private boolean open() {
  2. // NOTE: this cannot synchronize onsListeners, since
  3. // it's held in the main thread at least untilwe
  4. // return from here.
  5. //将返回的SensorEventQueue指针保存到sQueue里
  6. sQueue = sensors_create_queue();
  7. return true;
  8. }

将c++创建的SensorEventQueue对象地址保存到java层的一个变量里,这在android里面是很常见也很好用的方法

在open结束后,SensorThreadRunnable.run接下去调用sensors_data_poll来抓去sensor数据

staticnative int sensors_data_poll(int queue, float[] values, int[] status, long[]timestamp);

这个函数的第一个参数就是之前保存的c++层SensorEventQueue对象指针,看对应c++实现:

[cpp] view plaincopy
  1. staticjint
  2. sensors_data_poll(JNIEnv*env, jclass clazz, jint nativeQueue,
  3. jfloatArray values, jintArray status,jlongArray timestamp)
  4. {
  5. //强制类型转换
  6. sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue*>(nativeQueue));
  7. if (queue == 0) return -1;
  8. status_t res;
  9. ASensorEventevent;
  10. //从队列中读取数据
  11. res = queue->read(&event, 1);
  12. if (res == -EAGAIN) {
  13. res = queue->waitForEvent();
  14. if (res != NO_ERROR)
  15. return -1;
  16. res = queue->read(&event, 1);
  17. }
  18. if (res < 0)
  19. return -1;
  20. jint accuracy = event.vector.status;
  21. env->SetFloatArrayRegion(values, 0, 3,event.vector.v);
  22. env->SetIntArrayRegion(status, 0, 1,&accuracy);
  23. env->SetLongArrayRegion(timestamp, 0, 1,&event.timestamp);
  24. return event.sensor;
  25. }

先将java层传过来的对象地址强制类型转换成SensorEventQueue,然后调用 queue->read(&event, 1)读取sensor数据

[cpp] view plaincopy
  1. ssize_tSensorEventQueue::read(ASensorEvent* events, size_t numEvents)
  2. {
  3. ssize_t size =mSensorChannel->read(events, numEvents*sizeof(events[0]));
  4. LOGE_IF(size<0 && size!=-EAGAIN,
  5. "SensorChannel::read error(%s)", strerror(-size));
  6. if (size >= 0) {
  7. if (size % sizeof(events[0])) {
  8. // partial read!!! should neverhappen.
  9. LOGE("SensorEventQueue partialread (event-size=%u, read=%d)",
  10. sizeof(events[0]),int(size));
  11. return -EINVAL;
  12. }
  13. // returns number of events read
  14. size /= sizeof(events[0]);
  15. }
  16. returnsize;
  17. }

关于数据的具体传输,上一部分已经详细介绍,这里就不再描述

Jni部分sensors_data_poll在获取到sensor数据并返回到java层,SensorThreadRunnable.run在得到sensor数据后,通过下面代码将数据通过listener回调

[java] view plaincopy
  1. finalint size = sListeners.size();
  2. for(int i=0 ; i<size ; i++) {
  3. ListenerDelegate listener = sListeners.get(i);
  4. if (listener.hasSensor(sensorObject)) {
  5. // this is asynchronous (okay to call
  6. // with sListeners lock held).
  7. istener.onSensorChangedLocked(sensorObject,values,timestamp, accuracy);
  8. }
  9. }

就这样,通过registerlistener注册的listener就可以获取到想要的sensor数据,这样就可以了吗?还不行,上面只是说数据流是这么走的,SensorEventQueue::read现在读不到数据的,因为在sensor service那边,sensor还是inactive的,所以registerListener 在sSensorThread.startLocked()成功后,再调用enableSensorLocked来active指定sensor:

[java] view plaincopy
  1. private booleanenableSensorLocked(Sensor sensor, int delay) {
  2. boolean result = false;
  3. for (ListenerDelegate i : sListeners) {
  4. if (i.hasSensor(sensor)) {
  5. String name = sensor.getName();
  6. int handle =sensor.getHandle();
  7. result = sensors_enable_sensor(sQueue,name, handle, delay);
  8. break;
  9. }
  10. }
  11. return result;

sensors_enable_sensor,又一个jni函数,直接看对应c++函数:

[cpp] view plaincopy
  1. staticjboolean
  2. sensors_enable_sensor(JNIEnv*env, jclass clazz,
  3. jint nativeQueue, jstring name, jintsensor, jint delay)
  4. {
  5. sp<SensorEventQueue>queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));
  6. if (queue == 0) return JNI_FALSE;
  7. status_t res;
  8. if(delay >= 0) {
  9. res = queue->enableSensor(sensor,delay);
  10. } else {
  11. res = queue->disableSensor(sensor);
  12. }
  13. return res == NO_ERROR ? true : false;
  14. }

继续看queue->enableSensor

[cpp] view plaincopy
  1. status_tSensorEventQueue::enableSensor(int32_t handle, int32_t us) const {
  2. status_t err =mSensorEventConnection->enableDisable(handle, true);
  3. if (err == NO_ERROR) {
  4. mSensorEventConnection->setEventRate(handle, us2ns(us));
  5. }
  6. return err;
  7. }

调用mSensorEventConnection->enableDisable(handle,true)将对应的sensor激活。

Ok,激活后,SensorThreadRunnable.run中sensors_data_poll就可以拿到数据,并回调给注册的listener.

Android4.4 Sensor APP--HAL代码流程相关推荐

  1. android 6.0 高通平台sensor 工作机制及流程(原创)

    最近工作上有碰到sensor的相关问题,正好分析下其流程作个笔记. 这个笔记分三个部分: sensor硬件和驱动的工作机制 sensor 上层app如何使用 从驱动到上层app这中间的流程是如何 Se ...

  2. android 6.0 高通平台sensor 工作机制及流程

    最近工作上有碰到sensor的相关问题,正好分析下其流程作个笔记. 这个笔记分三个部分: sensor硬件和驱动的工作机制 sensor 上层app如何使用 从驱动到上层app这中间的流程是如何 Se ...

  3. Eboot代码流程 [转]

    Eboot代码流程 [转] Eboot代码流程                                              ----by nasiry                   ...

  4. Camera camx代码结构、编译、代码流程简介

    文章目录 一.camx 代码结构 二.camx 编译 三.camx 代码流程分析 转载链接: https://juejin.cn/post/6870358276425875463 https://ww ...

  5. 第1课第4.4节_Android硬件访问服务编写HAL代码

    android应用如何访问C库 - 落魄影子 - 博客频道 - CSDN.NET  http://blog.csdn.net/ab198604/article/details/51249303 And ...

  6. c++builder启动了怎么停止_App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析...

    在我的上一篇文章: AJie:按下电源键后竟然发生了这一幕 -- Android 系统启动流程分析​zhuanlan.zhihu.com 我们分析了系统在开机以后的一系列行为,其中最后一阶段 AMS( ...

  7. Android 系统(78)---《android framework常用api源码分析》之 app应用安装流程

    <android framework常用api源码分析>之 app应用安装流程 <android framework常用api源码分析>android生态在中国已经发展非常庞大 ...

  8. 分析APP的安装流程 API29

    先总结一下安装流程,以及比较重要的类 PackageInstallerActivity.java: 在文件管理器里点击apk后就会调用该类,主要用于显示要安装的apk的一些权限信息. InstallA ...

  9. 移动APP的测试流程及方法

    App的测试流程整理 1. APP测试基本流程 1.1流程图 1.2测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两三周(即15个工作日),根据项目情况以及版本质量可适当缩短或延长 ...

最新文章

  1. 看微软 Windows 30年发展简史,你用过最早的系统版本是什么?
  2. PyCairo 中的透明度
  3. matlab fig生成exe,MATLAB GUI多个m文件和fig如何生成exe文件
  4. IE6/7兼容问题:巧用label去除submit按钮的黑框线
  5. 带有MySQL和Bootstrap的Django 3教程和CRUD示例
  6. 关于SQL Server对于表的一些查询
  7. vue中怎么清空tab选项卡的缓存_vuejs 内置组件component实现tab切换懒加载和表单输入框内容的清空...
  8. k8s学习笔记-环境搭建篇
  9. 树莓派进阶之路 (027) - 在Linux中增加swap空间
  10. 数据结构实验1-线性表的顺序实现
  11. 中文近义词工具包,Synonyms 发布新版本 v3.16,支持词汇表扩大至 40w+
  12. 资源下载源码极致cms精纺资源网的模板整站源码
  13. php重定向和伪静态,「PHP重定向与伪静态区别」- 海风纷飞Blog
  14. 乔治城大学计算机专业,美国乔治城大学计算机
  15. Day02-线性代数-矩阵(DataWhale)
  16. #python 自动识别视频字幕
  17. 你应该补钙吗?看这篇就懂了
  18. [NOIP2018]普及组游记
  19. 老男孩脱产班Linux运维51期
  20. 《Java语言程序设计与数据结构》编程练习答案(第四章)(二)

热门文章

  1. Journey源码分析二:整体启动流程
  2. Memcached实战之单机部署----单实例/多实例
  3. FusionCharts图表右键菜单的各种典型示例
  4. 心情随笔之纸包子假新闻 [2007年7月25日]
  5. 提交注册信息到数据库中
  6. excel自动调整列宽_Excel双击鼠标的9种用法
  7. android 通知写法_Android架构设计MVP模式第(二)篇,如何减少类爆炸
  8. 计算机基础98均9,第三章 计算机基础 Windows98 (第二讲).ppt
  9. php点广告送积分,PHP猜一猜奇偶商城积分促销模式
  10. pdn阻抗测试_信号线的特征阻抗和PDN的阻抗区别