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