Android native CursorWindow数据保存原理

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

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

那么CursorWindow是如何实现的呢?

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

status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
    String8 ashmemName("CursorWindow: ");
    ashmemName.append(name);//文件名

    status_t result;
    int ashmemFd = ashmem_create_region(ashmemName.string(), size);
    if (ashmemFd < 0) {
        result = -errno;
    } else {
        result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
        if (result >= 0) {
            void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);//文件映射
            if (data == MAP_FAILED) {
                result = -errno;
            } else {
                result = ashmem_set_prot_region(ashmemFd, PROT_READ);
                if (result >= 0) {
                    CursorWindow* window = new CursorWindow(name, ashmemFd,
                            data, size, false /*readOnly*/);
                    result = window->clear();
                    if (!result) {
                        LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
                                "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                                window->mHeader->freeOffset,
                                window->mHeader->numRows,
                                window->mHeader->numColumns,
                                window->mSize, window->mData);
                        *outCursorWindow = window;
                        return OK;
                    }
                    delete window;
                }
            }
            ::munmap(data, size);
        }
        ::close(ashmemFd);
    }
    *outCursorWindow = NULL;
    return result;
}

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

status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
    String8 name = parcel->readString8();

    status_t result;
    int ashmemFd = parcel->readFileDescriptor();
    if (ashmemFd == int(BAD_TYPE)) {
        result = BAD_TYPE;
    } else {
        ssize_t size = ashmem_get_size_region(ashmemFd);
        if (size < 0) {
            result = UNKNOWN_ERROR;
        } else {
            int dupAshmemFd = ::dup(ashmemFd);
            if (dupAshmemFd < 0) {
                result = -errno;
            } else {
                void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
                if (data == MAP_FAILED) {
                    result = -errno;
                } else {
                    CursorWindow* window = new CursorWindow(name, dupAshmemFd,
                            data, size, true /*readOnly*/);
                    LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "
                            "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                            window->mHeader->freeOffset,
                            window->mHeader->numRows,
                            window->mHeader->numColumns,
                            window->mSize, window->mData);
                    *outCursorWindow = window;
                    return OK;
                }
                ::close(dupAshmemFd);
            }
        }
    }
    *outCursorWindow = NULL;
    return result;
}

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

原理图如下:

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

FiledSlot的定义如下:

    struct FieldSlot {
    private:
        int32_t type;//列所对应的数据的类型
        union {
            double d;
            int64_t l;
            struct {
                uint32_t offset;
                uint32_t size;
            } buffer;
        } data;//data的数据类型是union,当type所表示的是String或者Blob的时候,offset表示的就是保存真实数据的buffer的偏移量,size表示buffer的大小

        friend class CursorWindow;
    } __attribute((packed));

Android native CursorWindow数据保存原理

时间: 2024-10-01 02:56:33

Android native CursorWindow数据保存原理的相关文章

React-Native系列Android——Native与Javascript通信原理(二)

前一篇博客分析了Native端向Javascript端通信的全流程,这次来研究下Javascript端向Native端通信的全流程,与前篇恰好构成一个基本完整的通信机制. 本篇博客内容与前篇联系较大,有些分析过的东西这次就直接拿来用了,不再赘述,所以希望阅读这篇文章之前先熟悉下前篇: React-Native系列Android--Native与Javascript通信原理(一) http://blog.csdn.net/MegatronKings/article/details/51114278

React-Native系列Android——Native与Javascript通信原理(三)

前面两篇博客,详细分析了Native与Javascript通信的过程,可以满足绝大部分场景下Native和Javascript的相互调用,但是仍然有不健全的情况. 比如Javascript层要实时获取Native的一些状态,就需要Native被动地向Javascript层通信了.这个过程区别于通信第一篇中Native主动向Javascript层通信,本篇博客就来研究下这样一个被动回调的过程! 在阅读本篇博客前,希望能回顾下前两篇. React-Native系列Android--Native与Ja

React-Native系列Android——Native与Javascript通信原理(一)

React-Native最核心的是Native与Javascript之间的通信,而且是双向通信,Native层到Javascript层,Javascript层到Native层,虽说是两个方向,但实现上大同小异,我们先从Native层入手,研究一下Native调用Javascript的过程. 1.通信模型 Android应用层的程序语言是Java,React-Native在Native端的框架实现用的也是Java语言,所以实质上是Java与Javascript两种程序语言的调用. 其实这个过程,在

Android开发之数据保存(一)

保存到SharePreference 1.获取SharePreference getSharePreferences();名称参数通过第一个参数来指定,可在app中任何一个Context执行该方法 getPreferences();不需要提供文件名称 例如在一个Fragment中执行的示例: Context context = getActivity(); SharedPreferences sharedPref = context.getSharedPreferences( getString

Android应用程序组件Content Provider在应用程序之间共享数据的原理分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6967204 在Android系统中,不同的应用程序是不能直接读写对方的数据文件的,如果它们想共享数据的话,只能通过 Content Provider组件来实现.那么,Content Provider组件又是如何突破应用程序边界权限控制来实现在不同的应用程序之间共享数据的呢?在前面的文章中,我们已经简要介绍过它是通过 Binder进程间通信机制以

Android开发学习---android下的数据持久化,保存数据到rom文件,android_data目录下文件访问的权限控制

一.需求 做一个类似QQ登录似的app,将数据写到ROM文件里,并对数据进行回显. 二.截图 登录界面: 文件浏览器,查看文件的保存路径:/data/data/com.amos.datasave/files/LoginTest.txt------/data/data/(包名)/files/(文件名) 导出的文件内容: 三.实现代码 新建一个Android 工程.这里我选择的是2.1即API 7,进行开发的,其它都是默认下一步下一步即可. /datasave/res/layout/activity

Android Content Provider在应用程序之间共享数据的原理分析

本文参考Android应用程序组件Content Provider在应用程序之间共享数据的原理分析http://blog.csdn.net/luoshengyang/article/details/6967204和<Android系统源代码情景分析>,作者罗升阳. 0.总图流程图如下: 总体类图: 1.MainActivity进程向AriticlesProvider进程发送IContentProvider.QUERY_TRANSACTION 如图:第一步 ~/Android/framework

Android 数据保存

Android数据保存方法 android数据保存主要保存以下三种: 1.共享参数文件中保存简单的键值对数据: 2.保存任意的文件数据到Android的文件系统中: 3.使用SQLite数据库管理 保存键值集 通过使用SharePreferences API来保存简单的键值对数据. 共享参数文件的获取或创建: 可以通过以下两种方法来获取: getSharedPreferences()  该方法需要提供一个共享参数文件的名称标识,该方法可以在任意Context中调用 getPreferences(

Android数据保存之文件保存

前言: 上一篇文章写了在Android中利用SharedPreferences保存数据,SharedPreferences在保存数据的时候主要是保存一些应用程序的设置信息或者少量的用户信息,而且是以key-value形式保存的String类的信息,比較有局限性. 比方你须要保存从网络获取的图片到本地作为缓存数据,而且数量比較大.SharedPreferences就不能满足你的需求了,这个时候就要用到基本上全部平台都会用到的文件保存. Android中以文件形式把数据保存到磁盘上与其它平台基本上都