1 /* 2 * Copyright (C) 2015 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 com.android.crashreportprovider; 18 19 import android.content.ContentProvider; 20 import android.content.ContentValues; 21 import android.content.Intent; 22 import android.database.Cursor; 23 import android.database.MatrixCursor; 24 import android.net.Uri; 25 import android.os.FileObserver; 26 import android.os.FileUtils; 27 import android.os.ParcelFileDescriptor; 28 import android.os.UserHandle; 29 30 import java.io.File; 31 import java.io.FileNotFoundException; 32 import java.util.List; 33 34 public class CrashReportProvider extends ContentProvider { 35 private static final File sCrashReportDirectory = new File("/data/system/crash_reports/"); 36 private static FileObserver sFileObserver; 37 38 public static final String ACTION_CRASH_REPORT_ADDED = 39 "com.android.crashreportprovider.action.CRASH_REPORT_ADDED"; 40 41 public static final Uri URI = Uri.parse("content://com.android.crashreportprovider/"); 42 43 public final String COLUMN_NAME = "name"; 44 private final String[] DEFAULT_PROJECTION = { COLUMN_NAME }; 45 46 @Override onCreate()47 public boolean onCreate() { 48 if (sFileObserver == null) { 49 sFileObserver = new FileObserver(sCrashReportDirectory.getPath(), 50 FileObserver.CLOSE_WRITE) { 51 @Override 52 public void onEvent(int event, String path) { 53 if (path.endsWith(".meta")) { 54 final Intent intent = new Intent(ACTION_CRASH_REPORT_ADDED); 55 getContext().sendBroadcastAsUser(intent, UserHandle.OWNER, 56 android.Manifest.permission.READ_LOGS); 57 } 58 } 59 }; 60 sFileObserver.startWatching(); 61 } 62 return true; 63 } 64 65 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)66 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 67 String sortOrder) { 68 final MatrixCursor cursor = 69 new MatrixCursor(projection == null ? DEFAULT_PROJECTION : projection); 70 final File[] files = sCrashReportDirectory.listFiles(); 71 if (files != null) { 72 for (File file : files) { 73 final MatrixCursor.RowBuilder row = cursor.newRow(); 74 row.add(COLUMN_NAME, file.getName()); 75 } 76 } 77 return cursor; 78 } 79 80 @Override openFile(Uri uri, String mode)81 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 82 if (ParcelFileDescriptor.parseMode(mode) != ParcelFileDescriptor.MODE_READ_ONLY) { 83 throw new FileNotFoundException("Cannot to open: " + uri + ", mode = " + mode); 84 } 85 List<String> segments = uri.getPathSegments(); 86 if (segments.size() != 1 || !FileUtils.isValidExtFilename(segments.get(0))) { 87 throw new FileNotFoundException("Invalid path."); 88 } 89 return ParcelFileDescriptor.open(new File(sCrashReportDirectory, segments.get(0)), 90 ParcelFileDescriptor.MODE_READ_ONLY); 91 } 92 93 @Override getType(Uri uri)94 public String getType(Uri uri) { 95 return null; 96 } 97 98 @Override delete(Uri uri, String selection, String[] selectionArgs)99 public int delete(Uri uri, String selection, String[] selectionArgs) { 100 throw new UnsupportedOperationException("Cannot delete: " + uri); 101 } 102 103 @Override insert(Uri uri, ContentValues values)104 public Uri insert(Uri uri, ContentValues values) { 105 throw new UnsupportedOperationException("Cannot insert: " + uri); 106 } 107 108 @Override update(Uri uri, ContentValues values, String selection, String[] selectionArgs)109 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 110 throw new UnsupportedOperationException("Cannot update: " + uri); 111 } 112 } 113