am dc8d7048: Merge changes I7277880e,Ia5584bd6 into klp-dev

* commit 'dc8d704899716e97e59af8b6fe5f549e0229eda6':
  Provide calling package to ContentProviders.
  Separate root and document management.
This commit is contained in:
Jeff Sharkey
2013-09-06 09:29:05 -07:00
committed by Android Git Automerger
12 changed files with 198 additions and 65 deletions

View File

@@ -3172,6 +3172,7 @@ package android.app {
public class AppOpsManager { public class AppOpsManager {
method public int checkOp(int, int, java.lang.String); method public int checkOp(int, int, java.lang.String);
method public int checkOpNoThrow(int, int, java.lang.String); method public int checkOpNoThrow(int, int, java.lang.String);
method public void checkPackage(int, java.lang.String);
method public void finishOp(int, int, java.lang.String); method public void finishOp(int, int, java.lang.String);
method public void finishOp(int); method public void finishOp(int);
method public int noteOp(int, int, java.lang.String); method public int noteOp(int, int, java.lang.String);
@@ -5624,6 +5625,7 @@ package android.content {
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle); method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle);
method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final java.lang.String getCallingPackage();
method public final android.content.Context getContext(); method public final android.content.Context getContext();
method public final android.content.pm.PathPermission[] getPathPermissions(); method public final android.content.pm.PathPermission[] getPathPermissions();
method public final java.lang.String getReadPermission(); method public final java.lang.String getReadPermission();
@@ -20747,6 +20749,7 @@ package android.provider {
method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String); method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String); method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String); method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRootsUri(java.lang.String); method public static android.net.Uri buildRootsUri(java.lang.String);
method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String); method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String); method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);

View File

@@ -615,6 +615,23 @@ public class AppOpsManager {
return MODE_IGNORED; return MODE_IGNORED;
} }
/**
* Do a quick check to validate if a package name belongs to a UID.
*
* @throws SecurityException if the package name doesn't belong to the given
* UID, or if ownership cannot be verified.
*/
public void checkPackage(int uid, String packageName) {
try {
if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
throw new SecurityException(
"Package " + packageName + " does not belong to " + uid);
}
} catch (RemoteException e) {
throw new SecurityException("Unable to verify package ownership", e);
}
}
/** /**
* Make note of an application performing an operation. Note that you must pass * Make note of an application performing an operation. Note that you must pass
* in both the uid and name of the application to be checked; this function will verify * in both the uid and name of the application to be checked; this function will verify

View File

@@ -102,6 +102,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
private boolean mExported; private boolean mExported;
private boolean mNoPerms; private boolean mNoPerms;
private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>();
private Transport mTransport = new Transport(); private Transport mTransport = new Transport();
/** /**
@@ -194,8 +196,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder, return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal)); CancellationSignal.fromTransport(cancellationSignal));
} }
return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder, mCallingPackage.set(callingPkg);
CancellationSignal.fromTransport(cancellationSignal)); try {
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -208,7 +216,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues); return rejectInsert(uri, initialValues);
} }
return ContentProvider.this.insert(uri, initialValues); mCallingPackage.set(callingPkg);
try {
return ContentProvider.this.insert(uri, initialValues);
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -216,7 +229,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0; return 0;
} }
return ContentProvider.this.bulkInsert(uri, initialValues); mCallingPackage.set(callingPkg);
try {
return ContentProvider.this.bulkInsert(uri, initialValues);
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -238,7 +256,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
} }
} }
} }
return ContentProvider.this.applyBatch(operations); mCallingPackage.set(callingPkg);
try {
return ContentProvider.this.applyBatch(operations);
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -246,7 +269,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0; return 0;
} }
return ContentProvider.this.delete(uri, selection, selectionArgs); mCallingPackage.set(callingPkg);
try {
return ContentProvider.this.delete(uri, selection, selectionArgs);
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -255,7 +283,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0; return 0;
} }
return ContentProvider.this.update(uri, values, selection, selectionArgs); mCallingPackage.set(callingPkg);
try {
return ContentProvider.this.update(uri, values, selection, selectionArgs);
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -263,8 +296,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException { throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode); enforceFilePermission(callingPkg, uri, mode);
return ContentProvider.this.openFile( mCallingPackage.set(callingPkg);
uri, mode, CancellationSignal.fromTransport(cancellationSignal)); try {
return ContentProvider.this.openFile(
uri, mode, CancellationSignal.fromTransport(cancellationSignal));
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -272,13 +310,23 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException { throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode); enforceFilePermission(callingPkg, uri, mode);
return ContentProvider.this.openAssetFile( mCallingPackage.set(callingPkg);
uri, mode, CancellationSignal.fromTransport(cancellationSignal)); try {
return ContentProvider.this.openAssetFile(
uri, mode, CancellationSignal.fromTransport(cancellationSignal));
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
public Bundle call(String callingPkg, String method, String arg, Bundle extras) { public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras); mCallingPackage.set(callingPkg);
try {
return ContentProvider.this.call(method, arg, extras);
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -290,8 +338,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType, public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException { Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, "r"); enforceFilePermission(callingPkg, uri, "r");
return ContentProvider.this.openTypedAssetFile( mCallingPackage.set(callingPkg);
uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal)); try {
return ContentProvider.this.openTypedAssetFile(
uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
} finally {
mCallingPackage.set(null);
}
} }
@Override @Override
@@ -460,6 +513,28 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return mContext; return mContext;
} }
/**
* Return the package name of the caller that initiated the request being
* processed on the current thread. The returned package will have been
* verified to belong to the calling UID. Returns {@code null} if not
* currently processing a request.
* <p>
* This will always return {@code null} when processing
* {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
*
* @see Binder#getCallingUid()
* @see Context#grantUriPermission(String, Uri, int)
* @throws SecurityException if the calling package doesn't belong to the
* calling UID.
*/
public final String getCallingPackage() {
final String pkg = mCallingPackage.get();
if (pkg != null) {
mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
}
return pkg;
}
/** /**
* Change the permission required to read data from the content * Change the permission required to read data from the content
* provider. This is normally set for you from its manifest information * provider. This is normally set for you from its manifest information
@@ -529,8 +604,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
/** @hide */ /** @hide */
public final void setAppOps(int readOp, int writeOp) { public final void setAppOps(int readOp, int writeOp) {
if (!mNoPerms) { if (!mNoPerms) {
mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService(
Context.APP_OPS_SERVICE);
mTransport.mReadOp = readOp; mTransport.mReadOp = readOp;
mTransport.mWriteOp = writeOp; mTransport.mWriteOp = writeOp;
} }
@@ -1413,6 +1486,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
*/ */
if (mContext == null) { if (mContext == null) {
mContext = context; mContext = context;
mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService(
Context.APP_OPS_SERVICE);
mMyUid = Process.myUid(); mMyUid = Process.myUid();
if (info != null) { if (info != null) {
setReadPermission(info.readPermission); setReadPermission(info.readPermission);
@@ -1451,15 +1526,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return results; return results;
} }
/**
* @hide
* Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name
* of the calling package.
*/
public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) {
return call(method, arg, extras);
}
/** /**
* Call a provider-defined method. This can be used to implement * Call a provider-defined method. This can be used to implement
* interfaces that are cheaper and/or unnatural for a table-like * interfaces that are cheaper and/or unnatural for a table-like

View File

@@ -72,7 +72,9 @@ public final class DocumentsContract {
public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER"; public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER";
/** {@hide} */ /** {@hide} */
public static final String ACTION_MANAGE_DOCUMENTS = "android.provider.action.MANAGE_DOCUMENTS"; public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT";
/** {@hide} */
public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
/** /**
* Constants related to a document, including {@link Cursor} columns names * Constants related to a document, including {@link Cursor} columns names
@@ -346,6 +348,9 @@ public final class DocumentsContract {
*/ */
public static final String COLUMN_MIME_TYPES = "mime_types"; public static final String COLUMN_MIME_TYPES = "mime_types";
/** {@hide} */
public static final String MIME_TYPE_ITEM = "vnd.android.document/root";
/** /**
* Type of root that represents a storage service, such as a cloud-based * Type of root that represents a storage service, such as a cloud-based
* service. * service.
@@ -461,6 +466,17 @@ public final class DocumentsContract {
.authority(authority).appendPath(PATH_ROOT).build(); .authority(authority).appendPath(PATH_ROOT).build();
} }
/**
* Build Uri representing the given {@link Root#COLUMN_ROOT_ID} in a
* document provider.
*
* @see #getRootId(Uri)
*/
public static Uri buildRootUri(String authority, String rootId) {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority).appendPath(PATH_ROOT).appendPath(rootId).build();
}
/** /**
* Build Uri representing the recently modified documents of a specific * Build Uri representing the recently modified documents of a specific
* root. When queried, a provider will return zero or more rows with columns * root. When queried, a provider will return zero or more rows with columns

View File

@@ -34,7 +34,6 @@ import android.content.res.AssetFileDescriptor;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Point; import android.graphics.Point;
import android.net.Uri; import android.net.Uri;
import android.os.Binder;
import android.os.Bundle; import android.os.Bundle;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
@@ -42,8 +41,6 @@ import android.os.ParcelFileDescriptor.OnCloseListener;
import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Document;
import android.util.Log; import android.util.Log;
import com.android.internal.util.ArrayUtils;
import libcore.io.IoUtils; import libcore.io.IoUtils;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@@ -75,11 +72,12 @@ import java.io.FileNotFoundException;
public abstract class DocumentsProvider extends ContentProvider { public abstract class DocumentsProvider extends ContentProvider {
private static final String TAG = "DocumentsProvider"; private static final String TAG = "DocumentsProvider";
private static final int MATCH_ROOT = 1; private static final int MATCH_ROOTS = 1;
private static final int MATCH_RECENT = 2; private static final int MATCH_ROOT = 2;
private static final int MATCH_DOCUMENT = 3; private static final int MATCH_RECENT = 3;
private static final int MATCH_CHILDREN = 4; private static final int MATCH_DOCUMENT = 4;
private static final int MATCH_SEARCH = 5; private static final int MATCH_CHILDREN = 5;
private static final int MATCH_SEARCH = 6;
private String mAuthority; private String mAuthority;
@@ -93,7 +91,8 @@ public abstract class DocumentsProvider extends ContentProvider {
mAuthority = info.authority; mAuthority = info.authority;
mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mMatcher.addURI(mAuthority, "root", MATCH_ROOT); mMatcher.addURI(mAuthority, "root", MATCH_ROOTS);
mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT);
mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT); mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT); mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN); mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
@@ -256,7 +255,7 @@ public abstract class DocumentsProvider extends ContentProvider {
String[] selectionArgs, String sortOrder) { String[] selectionArgs, String sortOrder) {
try { try {
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
case MATCH_ROOT: case MATCH_ROOTS:
return queryRoots(projection); return queryRoots(projection);
case MATCH_RECENT: case MATCH_RECENT:
return queryRecentDocuments(getRootId(uri), projection); return queryRecentDocuments(getRootId(uri), projection);
@@ -285,6 +284,8 @@ public abstract class DocumentsProvider extends ContentProvider {
public final String getType(Uri uri) { public final String getType(Uri uri) {
try { try {
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
case MATCH_ROOT:
return DocumentsContract.Root.MIME_TYPE_ITEM;
case MATCH_DOCUMENT: case MATCH_DOCUMENT:
return getDocumentType(getDocumentId(uri)); return getDocumentType(getDocumentId(uri));
default: default:
@@ -328,15 +329,22 @@ public abstract class DocumentsProvider extends ContentProvider {
throw new UnsupportedOperationException("Update not supported"); throw new UnsupportedOperationException("Update not supported");
} }
/** {@hide} */ /**
* Implementation is provided by the parent class. Can be overridden to
* provide additional functionality, but subclasses <em>must</em> always
* call the superclass. If the superclass returns {@code null}, the subclass
* may implement custom behavior.
*
* @see #openDocument(String, String, CancellationSignal)
* @see #deleteDocument(String)
*/
@Override @Override
public final Bundle callFromPackage( public Bundle call(String method, String arg, Bundle extras) {
String callingPackage, String method, String arg, Bundle extras) {
final Context context = getContext(); final Context context = getContext();
if (!method.startsWith("android:")) { if (!method.startsWith("android:")) {
// Let non-platform methods pass through // Let non-platform methods pass through
return super.callFromPackage(callingPackage, method, arg, extras); return super.call(method, arg, extras);
} }
final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID); final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID);
@@ -364,7 +372,7 @@ public abstract class DocumentsProvider extends ContentProvider {
if (!callerHasManage) { if (!callerHasManage) {
final Uri newDocumentUri = DocumentsContract.buildDocumentUri( final Uri newDocumentUri = DocumentsContract.buildDocumentUri(
mAuthority, newDocumentId); mAuthority, newDocumentId);
context.grantUriPermission(callingPackage, newDocumentUri, context.grantUriPermission(getCallingPackage(), newDocumentUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);

View File

@@ -23,6 +23,7 @@ interface IAppOpsService {
// These first methods are also called by native code, so must // These first methods are also called by native code, so must
// be kept in sync with frameworks/native/include/binder/IAppOpsService.h // be kept in sync with frameworks/native/include/binder/IAppOpsService.h
int checkOperation(int code, int uid, String packageName); int checkOperation(int code, int uid, String packageName);
int checkPackage(int uid, String packageName);
int noteOperation(int code, int uid, String packageName); int noteOperation(int code, int uid, String packageName);
int startOperation(IBinder token, int code, int uid, String packageName); int startOperation(IBinder token, int code, int uid, String packageName);
void finishOperation(IBinder token, int code, int uid, String packageName); void finishOperation(IBinder token, int code, int uid, String packageName);

View File

@@ -30,11 +30,10 @@
<category android:name="android.intent.category.OPENABLE" /> <category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="*/*" /> <data android:mimeType="*/*" />
</intent-filter> </intent-filter>
<!-- data expected to point at existing root to manage -->
<intent-filter> <intent-filter>
<action android:name="android.provider.action.MANAGE_DOCUMENTS" /> <action android:name="android.provider.action.MANAGE_ROOT" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.document/directory" /> <data android:mimeType="vnd.android.document/root" />
</intent-filter> </intent-filter>
</activity> </activity>

View File

@@ -145,7 +145,7 @@ public class DocumentsActivity extends Activity {
mState.action = ACTION_CREATE; mState.action = ACTION_CREATE;
} else if (Intent.ACTION_GET_CONTENT.equals(action)) { } else if (Intent.ACTION_GET_CONTENT.equals(action)) {
mState.action = ACTION_GET_CONTENT; mState.action = ACTION_GET_CONTENT;
} else if (DocumentsContract.ACTION_MANAGE_DOCUMENTS.equals(action)) { } else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) {
mState.action = ACTION_MANAGE; mState.action = ACTION_MANAGE;
} }
@@ -171,12 +171,13 @@ public class DocumentsActivity extends Activity {
} }
if (mState.action == ACTION_MANAGE) { if (mState.action == ACTION_MANAGE) {
final Uri rootUri = intent.getData(); final Uri uri = intent.getData();
final RootInfo root = mRoots.findRoot(rootUri); final String rootId = DocumentsContract.getRootId(uri);
final RootInfo root = mRoots.getRoot(uri.getAuthority(), rootId);
if (root != null) { if (root != null) {
onRootPicked(root, true); onRootPicked(root, true);
} else { } else {
Log.w(TAG, "Failed to find root: " + rootUri); Log.w(TAG, "Failed to find root: " + uri);
finish(); finish();
} }
@@ -626,14 +627,24 @@ public class DocumentsActivity extends Activity {
// Replace selected file // Replace selected file
SaveFragment.get(fm).setReplaceTarget(doc); SaveFragment.get(fm).setReplaceTarget(doc);
} else if (mState.action == ACTION_MANAGE) { } else if (mState.action == ACTION_MANAGE) {
// Open the document // First try managing the document; we expect manager to filter
final Intent intent = new Intent(Intent.ACTION_VIEW); // based on authority, so we don't grant.
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
intent.setData(doc.uri); manage.setData(doc.uri);
try { try {
startActivity(intent); startActivity(manage);
} catch (ActivityNotFoundException ex) { } catch (ActivityNotFoundException ex) {
Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); // Fall back to viewing
final Intent view = new Intent(Intent.ACTION_VIEW);
view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
view.setData(doc.uri);
try {
startActivity(view);
} catch (ActivityNotFoundException ex2) {
Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
}
} }
} }
} }

View File

@@ -16,13 +16,9 @@
package com.android.documentsui; package com.android.documentsui;
import android.util.Log;
import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentInfo;
import com.android.internal.util.Predicate; import com.android.internal.util.Predicate;
import java.util.Arrays;
public class MimePredicate implements Predicate<DocumentInfo> { public class MimePredicate implements Predicate<DocumentInfo> {
private final String[] mFilters; private final String[] mFilters;

View File

@@ -567,8 +567,7 @@ public class SettingsProvider extends ContentProvider {
* Fast path that avoids the use of chatty remoted Cursors. * Fast path that avoids the use of chatty remoted Cursors.
*/ */
@Override @Override
public Bundle callFromPackage(String callingPackage, String method, String request, public Bundle call(String method, String request, Bundle args) {
Bundle args) {
int callingUser = UserHandle.getCallingUserId(); int callingUser = UserHandle.getCallingUserId();
if (args != null) { if (args != null) {
int reqUser = args.getInt(Settings.CALL_METHOD_USER_KEY, callingUser); int reqUser = args.getInt(Settings.CALL_METHOD_USER_KEY, callingUser);
@@ -623,7 +622,7 @@ public class SettingsProvider extends ContentProvider {
// Also need to take care of app op. // Also need to take care of app op.
if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SETTINGS, Binder.getCallingUid(), if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SETTINGS, Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) { getCallingPackage()) != AppOpsManager.MODE_ALLOWED) {
return null; return null;
} }

View File

@@ -551,6 +551,17 @@ public class AppOpsService extends IAppOpsService.Stub {
} }
} }
@Override
public int checkPackage(int uid, String packageName) {
synchronized (this) {
if (getOpsLocked(uid, packageName, true) != null) {
return AppOpsManager.MODE_ALLOWED;
} else {
return AppOpsManager.MODE_ERRORED;
}
}
}
@Override @Override
public int noteOperation(int code, int uid, String packageName) { public int noteOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid); verifyIncomingUid(uid);
@@ -560,7 +571,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (ops == null) { if (ops == null) {
if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+ " package " + packageName); + " package " + packageName);
return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_ERRORED;
} }
Op op = getOpLocked(ops, code, true); Op op = getOpLocked(ops, code, true);
if (op.duration == -1) { if (op.duration == -1) {
@@ -594,7 +605,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (ops == null) { if (ops == null) {
if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ " package " + packageName); + " package " + packageName);
return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_ERRORED;
} }
Op op = getOpLocked(ops, code, true); Op op = getOpLocked(ops, code, true);
final int switchCode = AppOpsManager.opToSwitch(code); final int switchCode = AppOpsManager.opToSwitch(code);

View File

@@ -24,6 +24,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.net.Uri; import android.net.Uri;
import android.os.Binder;
import android.os.Debug; import android.os.Debug;
import android.os.DropBoxManager; import android.os.DropBoxManager;
import android.os.FileUtils; import android.os.FileUtils;
@@ -265,8 +266,13 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
} }
public boolean isTagEnabled(String tag) { public boolean isTagEnabled(String tag) {
return !"disabled".equals(Settings.Global.getString( final long token = Binder.clearCallingIdentity();
mContentResolver, Settings.Global.DROPBOX_TAG_PREFIX + tag)); try {
return !"disabled".equals(Settings.Global.getString(
mContentResolver, Settings.Global.DROPBOX_TAG_PREFIX + tag));
} finally {
Binder.restoreCallingIdentity(token);
}
} }
public synchronized DropBoxManager.Entry getNextEntry(String tag, long millis) { public synchronized DropBoxManager.Entry getNextEntry(String tag, long millis) {