Files
frameworks_base/packages/Shell/src/com/android/shell/HeapDumpProvider.java
Kweku Adams 4d345d7af1 Move heap dump sharing to SHELL.
The system shouldn't be granting read URI permissions as itself. This
means that heap dumps aren't successfully shared. Moving the heap dump
sharing mechanism to SHELL, which already has the permission to dump
heaps so that dumps can be shared properly.

The ActivityManagerService changes are submitted separately.

Bug: 126885951
Bug: 135150619
Test: collect a heap dump and confirm it's successfully shared with an app
Test: do manual test on a secondary user & confirm it's not available to
other user

Change-Id: I6fad69280b5124c8ec2d3b4bef0f7dddb6a9422c
2019-10-29 15:17:42 -07:00

102 lines
3.2 KiB
Java

/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.shell;
import android.annotation.NonNull;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import java.io.File;
import java.io.FileNotFoundException;
/** ContentProvider to write and access heap dumps. */
public class HeapDumpProvider extends ContentProvider {
private static final String FILENAME_SUFFIX = "_javaheap.bin";
private static final Object sLock = new Object();
private File mRoot;
@Override
public boolean onCreate() {
synchronized (sLock) {
mRoot = new File(getContext().createCredentialProtectedStorageContext().getFilesDir(),
"heapdumps");
return mRoot.mkdir();
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return null;
}
@Override
public String getType(Uri uri) {
return "application/octet-stream";
}
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException("Insert not allowed.");
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
String path = sanitizePath(uri.getEncodedPath());
String tag = Uri.decode(path);
return (new File(mRoot, tag)).delete() ? 1 : 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Update not allowed.");
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
String path = sanitizePath(uri.getEncodedPath());
String tag = Uri.decode(path);
final int pMode;
if (Binder.getCallingUid() == Process.SYSTEM_UID) {
pMode = ParcelFileDescriptor.MODE_CREATE
| ParcelFileDescriptor.MODE_TRUNCATE
| ParcelFileDescriptor.MODE_WRITE_ONLY;
} else {
pMode = ParcelFileDescriptor.MODE_READ_ONLY;
}
synchronized (sLock) {
return ParcelFileDescriptor.open(new File(mRoot, tag), pMode);
}
}
@NonNull
static Uri makeUri(@NonNull String procName) {
return Uri.parse("content://com.android.shell.heapdump/" + procName + FILENAME_SUFFIX);
}
private String sanitizePath(String path) {
return path.replaceAll("[^a-zA-Z0-9_.]", "");
}
}