xref: /aosp_15_r20/cts/tests/tests/content/src/android/content/cts/CursorWindowContentProvider.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.content.cts;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.ContentProvider;
22 import android.content.ContentValues;
23 import android.database.AbstractWindowedCursor;
24 import android.database.Cursor;
25 import android.database.CursorWindow;
26 import android.net.Uri;
27 import android.os.Parcel;
28 import android.os.ParcelFileDescriptor;
29 import android.util.Log;
30 
31 import java.io.File;
32 
33 /**
34  * Content provider that uses a custom {@link CursorWindow} to inject file descriptor
35  * pointing to another ashmem region having window slots with references outside of allowed ranges.
36  *
37  * <p>Used in {@link ContentProviderCursorWindowTest}
38  */
39 public class CursorWindowContentProvider extends ContentProvider {
40     private static final String TAG = "CursorWindowContentProvider";
41     static {
42         System.loadLibrary("nativecursorwindow_jni");
43     }
44 
45     private String mTempFilename;
46 
47     @Override
onCreate()48     public boolean onCreate() {
49         mTempFilename = (new File(getContext().getFilesDir(), "shared-file.dat")).getAbsolutePath();
50         return true;
51     }
52 
53     @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)54     public Cursor query(Uri uri, String[] projection, String selection,
55             String[] selectionArgs, String sortOrder) {
56         AbstractWindowedCursor cursor = new AbstractWindowedCursor() {
57             @Override
58             public int getCount() {
59                 return 1;
60             }
61 
62             @Override
63             public String[] getColumnNames() {
64                 return new String[] {"a"};
65             }
66         };
67         cursor.setWindow(new InjectingCursorWindow("TmpWindow"));
68         return cursor;
69     }
70 
71     class InjectingCursorWindow extends CursorWindow {
InjectingCursorWindow(String name)72         InjectingCursorWindow(String name) {
73             super(name);
74         }
75 
76         @Override
writeToParcel(Parcel dest, int flags)77         public void writeToParcel(Parcel dest, int flags) {
78             Parcel tmp = Parcel.obtain();
79 
80             super.writeToParcel(tmp, flags);
81             tmp.setDataPosition(0);
82             // Find location of file descriptor
83             int fdPos = -1;
84             while (tmp.dataAvail() > 0) {
85                 fdPos = tmp.dataPosition();
86                 int frameworkFdMarker = tmp.readInt();
87                 if (frameworkFdMarker == 0x66642a85 /* BINDER_TYPE_FD */) {
88                     break;
89                 }
90             }
91             if (fdPos == -1) {
92                 tmp.recycle();
93                 throw new IllegalStateException("File descriptor not found in the output of "
94                         + "CursorWindow.writeToParcel");
95             }
96             // Write reply with replaced file descriptor
97             ParcelFileDescriptor evilFd = ParcelFileDescriptor
98                     .adoptFd(makeNativeCursorWindowFd(mTempFilename, 1000, 1000, true));
99             dest.appendFrom(tmp, 0, fdPos);
100             dest.writeFileDescriptor(evilFd.getFileDescriptor());
101             tmp.setDataPosition(dest.dataPosition());
102             dest.appendFrom(tmp, dest.dataPosition(), tmp.dataAvail());
103             tmp.recycle();
104         }
105     }
106 
makeNativeCursorWindowFd(String filename, int offset, int size, boolean isBlob)107     private static native int makeNativeCursorWindowFd(String filename,
108             int offset, int size, boolean isBlob);
109 
110     // Stubs
111 
112     @Override
delete(Uri uri, String selection, String[] selectionArgs)113     public int delete(Uri uri, String selection, String[] selectionArgs) {
114         Log.e(TAG, "delete() not implemented");
115         return 0;
116     }
117 
118     @Override
getType(Uri uri)119     public String getType(Uri uri) {
120         Log.e(TAG, "getType() not implemented");
121         return "";
122     }
123 
124     @Override
insert(@onNull Uri uri, @Nullable ContentValues values)125     public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
126         Log.e(TAG, "insert() not implemented");
127         return null;
128     }
129 
130     @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)131     public int update(Uri uri, ContentValues values, String selection,
132             String[] selectionArgs) {
133         Log.e(TAG, "update() not implemented");
134         return 0;
135     }
136 
137 }
138