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

简介:
 Step 7. ContentProviderProxy.query
      这个函数定义在frameworks/base/core/java/android/content/ContentProviderNative.java文件中:
  1. final class ContentProviderProxy implements IContentProvider {  
  2.     ......  
  3.   
  4.     public Cursor query(Uri url, String[] projection, String selection,  
  5.             String[] selectionArgs, String sortOrder) throws RemoteException {  
  6.         //TODO make a pool of windows so we can reuse memory dealers  
  7.         CursorWindow window = new CursorWindow(false /* window will be used remotely */);  
  8.         BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();  
  9.         IBulkCursor bulkCursor = bulkQueryInternal(  
  10.             url, projection, selection, selectionArgs, sortOrder,  
  11.             adaptor.getObserver(), window,  
  12.             adaptor);  
  13.         if (bulkCursor == null) {  
  14.             return null;  
  15.         }  
  16.         return adaptor;  
  17.     }  
  18.   
  19.     ......  
  20. }  
        这个函数首先会创建一个CursorWindow对象,前面已经说过,这个CursorWindow对象包含了一块匿名共享内存,它的作用是把这块匿名共享内存通过Binder进程间通信机制传给Content Proivder,好让Content Proivder在里面返回所请求的数据。下面我们就先看看这个CursorWindow对象的创建过程,重点关注它是如何在内部创建匿名共享内存的,然后再回过头来看看它调用bulkQueryInternal函数来做了些什么事情。
        CursorWindow类定义在frameworks/base/core/java/android/database/CursorWindow.java文件中,我们来看看它的构造函数的实现:
  1. public class CursorWindow extends SQLiteClosable implements Parcelable {  
  2.     ......  
  3.   
  4.     private int nWindow;  
  5.   
  6.     ......  
  7.   
  8.     public CursorWindow(boolean localWindow) {  
  9.         ......  
  10.   
  11.         native_init(localWindow);  
  12.     }  
  13.   
  14.     ......  
  15. }  
 
        它主要调用本地方法native_init来执行初始化的工作,主要就是创建匿名共享内存了,传进来的参数localWindow为false,表示这个匿名共享内存只能通过远程调用来访问,即前面我们所说的,通过Content Proivder返回来的Cursor接口来访问这块匿名共享内存里面的数据。
        Step 8. CursorWindow.native_init
        这是一个JNI方法,它对应定义在frameworks/base/core/jni/android_database_CursorWindow.cpp文件中的native_init_empty函数:
  1. static JNINativeMethod sMethods[] =  
  2. {  
  3.      /* name, signature, funcPtr */  
  4.     {"native_init""(Z)V", (void *)native_init_empty},  
  5.     ......  
  6. };  
         函数native_init_empty的定义如下所示:
  1. static void native_init_empty(JNIEnv * env, jobject object, jboolean localOnly)  
  2. {  
  3.     ......  
  4.   
  5.     CursorWindow * window;  
  6.   
  7.     window = new CursorWindow(MAX_WINDOW_SIZE);  
  8.     ......  
  9.   
  10.     if (!window->initBuffer(localOnly)) {  
  11.         ......  
  12.     }  
  13.   
  14.     ......  
  15.     SET_WINDOW(env, object, window);  
  16. }  
         这个函数在C++层创建了一个CursorWindow对象,然后通过调用SET_WINDOW宏来把这个C++层的CursorWindow对象与Java层的CursorWindow对象关系起来:
  1. #define SET_WINDOW(env, object, window) (env->SetIntField(object, gWindowField, (int)window))  
         这里的gWindowField即定义为Java层的CursorWindow对象中的nWindow成员变量:
  1. static jfieldID gWindowField;  
  2.   
  3. ......  
  4.   
  5. int register_android_database_CursorWindow(JNIEnv * env)  
  6. {  
  7.     jclass clazz;  
  8.   
  9.     clazz = env->FindClass("android/database/CursorWindow");  
  10.     ......  
  11.   
  12.     gWindowField = env->GetFieldID(clazz, "nWindow""I");  
  13.   
  14.     ......  
  15. }  
        这种用法在Android应用程序框架层中非常普遍。
 
        下面我们重点关注C++层的CursorWindow对象的initBuffer函数的实现。
        Step 9. CursorWindow.initBuffer
        C++层的CursorWindow类定义在frameworks/base/core/jni/CursorWindow.cpp文件中:
  1. bool CursorWindow::initBuffer(bool localOnly)  
  2. {  
  3.     ......  
  4.   
  5.     sp<MemoryHeapBase> heap;  
  6.     heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow");  
  7.     if (heap != NULL) {  
  8.         mMemory = new MemoryBase(heap, 0, mMaxSize);  
  9.         if (mMemory != NULL) {  
  10.             mData = (uint8_t *) mMemory->pointer();  
  11.             if (mData) {  
  12.                 mHeader = (window_header_t *) mData;  
  13.                 mSize = mMaxSize;  
  14.   
  15.                 ......  
  16.             }  
  17.         }  
  18.         ......  
  19.     } else {  
  20.         ......  
  21.     }  
  22. }  
        这里我们就可以很清楚地看到,在CursorWindow类的内部有一个成员变量mMemory,它的类型是MemoryBase。MemoryBase类为我们封装了匿名共享内存的访问以及在进程间的传输等问题,具体可以参考前面一篇文章 Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析 ,这里就不再详述了。
 
        通过Step 8和Step 9两步,用来在第三方应用程序和Content Provider之间传输数据的媒介就准备好了,我们回到Step 7中,看看系统是如何把这个匿名共享存传递给Content Provider使用的。在Step 7中,最后调用bulkQueryInternal函数来进一步操作。
        Step 10. ContentProviderProxy.bulkQueryInternal
      这个函数定义在frameworks/base/core/java/android/content/ContentProviderNative.java文件中:
 
 
  1. final class ContentProviderProxy implements IContentProvider   
  2. {   
  3.     ......   
  4.    
  5.     private IBulkCursor bulkQueryInternal(   
  6.             Uri url, String[] projection,   
  7.             String selection, String[] selectionArgs, String sortOrder,   
  8.             IContentObserver observer, CursorWindow window,   
  9.             BulkCursorToCursorAdaptor adaptor) throws RemoteException {   
  10.         Parcel data = Parcel.obtain();   
  11.         Parcel reply = Parcel.obtain();   
  12.    
  13.         data.writeInterfaceToken(IContentProvider.descriptor);   
  14.    
  15.         url.writeToParcel(data, 0);   
  16.         int length = 0;   
  17.         if (projection != null) {   
  18.             length = projection.length;   
  19.         }   
  20.         data.writeInt(length);   
  21.         for (int i = 0; i < length; i++) {   
  22.             data.writeString(projection[i]);   
  23.         }   
  24.         data.writeString(selection);   
  25.         if (selectionArgs != null) {   
  26.             length = selectionArgs.length;   
  27.         } else {   
  28.             length = 0;   
  29.         }   
  30.         data.writeInt(length);   
  31.         for (int i = 0; i < length; i++) {   
  32.             data.writeString(selectionArgs[i]);   
  33.         }   
  34.         data.writeString(sortOrder);   
  35.         data.writeStrongBinder(observer.asBinder());   
  36.         window.writeToParcel(data, 0);   
  37.    
  38.         // Flag for whether or not we want the number of rows in the   
  39.         // cursor and the position of the "_id" column index (or -1 if   
  40.         // non-existent).  Only to be returned if binder != null.   
  41.         final boolean wantsCursorMetadata = (adaptor != null);   
  42.         data.writeInt(wantsCursorMetadata ? 1 : 0);   
  43.    
  44.         mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);   
  45.    
  46.         DatabaseUtils.readExceptionFromParcel(reply);   
  47.    
  48.         IBulkCursor bulkCursor = null;   
  49.         IBinder bulkCursorBinder = reply.readStrongBinder();   
  50.         if (bulkCursorBinder != null) {   
  51.             bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);   
  52.    
  53.             if (wantsCursorMetadata) {   
  54.                 int rowCount = reply.readInt();   
  55.                 int idColumnPosition = reply.readInt();   
  56.                 if (bulkCursor != null) {   
  57.                     adaptor.set(bulkCursor, rowCount, idColumnPosition);   
  58.                 }   
  59.             }   
  60.         }   
  61.    
  62.         data.recycle();   
  63.         reply.recycle();   
  64.    
  65.         return bulkCursor;   
  66.     }   
  67.    
  68.     ......   
  69. }   
     这个函数有点长,不过它的逻辑很简单,就是把查询参数都写到一个Parcel对象data中去,然后通过下面Binder进程间通信机制把查询请求传给Content Provider处理: 
  1. mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);  
      从这个Binder调用返回以后,就会得到一个IBulkCursor接口,它是一个Binder引用,实际是指向在Content Provider这一侧创建的一个CursorToBulkCursorAdaptor对象,后面我们将会看到。有了这个IBulkCursor接口之后,我们就可以通过Binder进程间调用来访问从Content Provider中查询得到的数据了。这个IBulkCursor接口最终最设置了上面Step 7中创建的BulkCursorToCursorAdaptor对象adaptor中去:
 
 
  1. adaptor.set(bulkCursor, rowCount, idColumnPosition);  
      BulkCursorToCursorAdaptor类实现了Cursor接口,因此,我们可以通过Curosr接口来访问这些查询得到的共享数据。
 
      在前面把查询参数写到Parcel对象data中去的过程中,有两个步骤是比较重要的,分别下面这段执行语句:
  1. window.writeToParcel(data, 0);  
  2.   
  3. // Flag for whether or not we want the number of rows in the  
  4. // cursor and the position of the "_id" column index (or -1 if  
  5. // non-existent).  Only to be returned if binder != null.  
  6. final boolean wantsCursorMetadata = (adaptor != null);  
  7. data.writeInt(wantsCursorMetadata ? 1 : 0);  
      调用window.writeToParcel是把window对象内部的匿名共享内存块通过Binder进程间通信机制传输给Content Provider来使用;而当传进来的参数adaptor不为null时,就会往data中写入一个整数1,表示让Content Provider把查询得到数据的元信息一起返回来,例如数据的行数、数据行的ID列的索引位置等信息,这个整数值会促使Content Provider把前面说的IBulkCursor接口返回给第三方应用程序之前,真正执行一把数据库查询操作,后面我们将看到这个过程。
 
      现在,我们重点来关注一下CursorWindow类的writeToParcel函数,看看它是如何把它内部的匿名共享内存对象写到数据流data中去的。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966999,如需转载请自行联系原作者
目录
相关文章
|
1月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
175 4
|
1月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
1月前
|
缓存 Java 数据库
Android的ANR原理
【10月更文挑战第18天】了解 ANR 的原理对于开发高质量的 Android 应用至关重要。通过合理的设计和优化,可以有效避免 ANR 的发生,提升应用的性能和用户体验。
126 56
|
28天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
30 8
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
86 15
Android 系统缓存扫描与清理方法分析
|
1月前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
40 1
|
2月前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
2月前
|
XML 前端开发 Android开发
Android View的绘制流程和原理详细解说
Android View的绘制流程和原理详细解说
55 3
|
3月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
158 3
|
3月前
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
51 2