Android native CursorWindow数据保存原理

转载 2017年01月03日 14:33:51

转自http://blog.csdn.net/ifloveelse/article/details/28394103



我们通过Uri查询数据库所得到的数据集,保存在native层的CursorWindow中。CursorWindow的实质是共享内存的抽象,以实现跨进程数据共享。共享内存所采用的实现方式是文件映射。

在ContentProvider端透过SQLiteDatabase的封装查询到的数据集保存在CursorWindow所指向的共享内存中,然后通过Binder把这片共享内存传递到ContentResolver端,即查询端。这样客户就可以通过Cursor来访问这块共享内存中的数据集了。

那么CursorWindow是如何实现的呢?

1.通过Create静态函数来创建

  1. status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {  
  2.     String8 ashmemName("CursorWindow: ");  
  3.     ashmemName.append(name);//文件名  
  4.   
  5.     status_t result;  
  6.     int ashmemFd = ashmem_create_region(ashmemName.string(), size);  
  7.     if (ashmemFd < 0) {  
  8.         result = -errno;  
  9.     } else {  
  10.         result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);  
  11.         if (result >= 0) {  
  12.             void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);//文件映射  
  13.             if (data == MAP_FAILED) {  
  14.                 result = -errno;  
  15.             } else {  
  16.                 result = ashmem_set_prot_region(ashmemFd, PROT_READ);  
  17.                 if (result >= 0) {  
  18.                     CursorWindow* window = new CursorWindow(name, ashmemFd,  
  19.                             data, size, false /*readOnly*/);  
  20.                     result = window->clear();  
  21.                     if (!result) {  
  22.                         LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "  
  23.                                 "numRows=%d, numColumns=%d, mSize=%d, mData=%p",  
  24.                                 window->mHeader->freeOffset,  
  25.                                 window->mHeader->numRows,  
  26.                                 window->mHeader->numColumns,  
  27.                                 window->mSize, window->mData);  
  28.                         *outCursorWindow = window;  
  29.                         return OK;  
  30.                     }  
  31.                     delete window;  
  32.                 }  
  33.             }  
  34.             ::munmap(data, size);  
  35.         }  
  36.         ::close(ashmemFd);  
  37.     }  
  38.     *outCursorWindow = NULL;  
  39.     return result;  
  40. }  

2.通过文件句柄来创建。这种case应该是在客户端的创建出一个CursorWindow所采用。

  1. status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {  
  2.     String8 name = parcel->readString8();  
  3.   
  4.     status_t result;  
  5.     int ashmemFd = parcel->readFileDescriptor();  
  6.     if (ashmemFd == int(BAD_TYPE)) {  
  7.         result = BAD_TYPE;  
  8.     } else {  
  9.         ssize_t size = ashmem_get_size_region(ashmemFd);  
  10.         if (size < 0) {  
  11.             result = UNKNOWN_ERROR;  
  12.         } else {  
  13.             int dupAshmemFd = ::dup(ashmemFd);  
  14.             if (dupAshmemFd < 0) {  
  15.                 result = -errno;  
  16.             } else {  
  17.                 void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);  
  18.                 if (data == MAP_FAILED) {  
  19.                     result = -errno;  
  20.                 } else {  
  21.                     CursorWindow* window = new CursorWindow(name, dupAshmemFd,  
  22.                             data, size, true /*readOnly*/);  
  23.                     LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "  
  24.                             "numRows=%d, numColumns=%d, mSize=%d, mData=%p",  
  25.                             window->mHeader->freeOffset,  
  26.                             window->mHeader->numRows,  
  27.                             window->mHeader->numColumns,  
  28.                             window->mSize, window->mData);  
  29.                     *outCursorWindow = window;  
  30.                     return OK;  
  31.                 }  
  32.                 ::close(dupAshmemFd);  
  33.             }  
  34.         }  
  35.     }  
  36.     *outCursorWindow = NULL;  
  37.     return result;  
  38. }  

CursorWindow是如何保存查询到的数据集的呢?

原理图如下:

没一行所对应的数据采用FieldSlot数组来表示。图中黄色部分表示一行所对应的数据。如果列所对应的数据是long或者double,那么就直接保存在FieldSlot中,如果是Blob或者String,那么就在FieldSlot中保存数据的便宜量。

FiledSlot的定义如下:

  1. struct FieldSlot {  
  2. private:  
  3.     int32_t type;//列所对应的数据的类型  
  4.     union {  
  5.         double d;  
  6.         int64_t l;  
  7.         struct {  
  8.             uint32_t offset;  
  9.             uint32_t size;  
  10.         } buffer;  
  11.     } data;//data的数据类型是union,当type所表示的是String或者Blob的时候,offset表示的就是保存真实数据的buffer的偏移量,size表示buffer的大小  
  12.   
  13.     friend class CursorWindow;  
  14. } __attribute((packed)); 

Android native CursorWindow数据保存原理

Android SQLite数据集buffer实现原理
  • Sailingthink
  • Sailingthink
  • 2014年06月04日 10:35
  • 3452

React native for Android 初步实践[原理剖析]

摘要: Facebook 于2015年9月15日推出react native for Android 版本, 加上2014年底已经开源的IOS版本,至此RN (react-native)真正成为跨平台...
  • h416756139
  • h416756139
  • 2016年06月02日 11:24
  • 7870

从源码看ANDROID中SQLITE是怎么通过CURSORWINDOW读DB的

从源码看ANDROID中SQLITE是怎么通过CURSORWINDOW读DB
  • u011453773
  • u011453773
  • 2016年02月24日 15:34
  • 1244

React Native运行原理解析

Facebook 于2015年9月15日推出react native for Android 版本, 加上2014年底已经开源的IOS版本,至此RN (react-native)真正成为跨平台的客户端...
  • xiangzhihong8
  • xiangzhihong8
  • 2016年09月22日 15:54
  • 23757

IllegalStateExceptio: Couldn't read row * from CursorWindow due to CursorWindow.nativeGetLong

本人在开发云端备份短信查询短信过程中遇到了如下报错问题,被这个报错折腾了将近一天时间,现将解决思路Mark,错误之处请勘误。 05-13 19:24:23.635847 25932 28515 E ...
  • HJQXCode
  • HJQXCode
  • 2017年06月05日 10:15
  • 192

深入理解React Native页面构建渲染原理

前言React Native 是最近非常火的一个话题,因为它的语法简介,跨平台等特性,赢得了各大平台的青睐,虽然前期是有一些坑。基本概念解释React 是一套可以用简洁的语法高效绘制 DOM 的框架,...
  • xiangzhihong8
  • xiangzhihong8
  • 2017年01月14日 11:21
  • 12254

Android Cursor 源码分析

1. 本文目的 Android ContentProvider提供了进程间数据交换的一种机制。而数据库的查询就是这种机制的应用。那么app通过Uri查询数据库而得到的Cursor究竟是个什么东西...
  • hlglinglong
  • hlglinglong
  • 2014年10月24日 18:44
  • 1044

android数据库操作问题:could not allocate cursorwindow,errno:-12

android上手没多久,正好涉及到数据库操作,用了android自带的sqlite。     正好需要往数据库导点数据进去测试用,然后直接在主进程写数据库了。。。然后,就出现这个问题:could n...
  • OHRadiance
  • OHRadiance
  • 2015年02月24日 23:54
  • 1668

【React Native】从源码一步一步解析它的实现原理

本文标签: ReactNative React是什么 Native是什么 NativeApp App开发模式 一、React Native背景 有没有朋友想过一个问题,为什么取...
  • littlesmallless
  • littlesmallless
  • 2017年03月29日 23:17
  • 1514

CursorWindow can not be created due to cursor [memory] leak

记录了Android系统上由于cursor泄露导致内存耗尽(error -12)导致的CursorWindow不能再创建的Issue。 [Symptom] 08-30 20:27:36.751 E...
  • zirconsdu
  • zirconsdu
  • 2013年04月03日 15:04
  • 6536
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android native CursorWindow数据保存原理
举报原因:
原因补充:

(最多只允许输入30个字)