Moved URI grants code out of ActivityManagerService to its own service (13/n)
Allows for other services like window manager to call uri grants without
holding AM service lock.
Bug: 80414790
Test: Existing tests pass.
Change-Id: Ie5b4ddb19a2cedff09332dbeb56bcd9292fd18ac
diff --git a/Android.bp b/Android.bp
index 8c81534..28383ba 100644
--- a/Android.bp
+++ b/Android.bp
@@ -85,6 +85,7 @@
"core/java/android/app/IUidObserver.aidl",
"core/java/android/app/IUiAutomationConnection.aidl",
"core/java/android/app/IUiModeManager.aidl",
+ "core/java/android/app/IUriGrantsManager.aidl",
"core/java/android/app/IUserSwitchObserver.aidl",
"core/java/android/app/IWallpaperManager.aidl",
"core/java/android/app/IWallpaperManagerCallback.aidl",
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 3f579bc..90fa8ca 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2559,7 +2559,6 @@
return clearApplicationUserData(mContext.getPackageName(), null);
}
-
/**
* Permits an application to get the persistent URI permissions granted to another.
*
@@ -2571,17 +2570,13 @@
* @return list of granted URI permissions
*
* @hide
+ * @deprecated use {@link UriGrantsManager#getGrantedUriPermissions(String)} instead.
*/
+ @Deprecated
public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
@Nullable String packageName) {
- try {
- @SuppressWarnings("unchecked")
- final ParceledListSlice<GrantedUriPermission> castedList = getService()
- .getGrantedUriPermissions(packageName, mContext.getUserId());
- return castedList;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return ((UriGrantsManager) mContext.getSystemService(Context.URI_GRANTS_SERVICE))
+ .getGrantedUriPermissions(packageName);
}
/**
@@ -2592,14 +2587,12 @@
* @param packageName application to clear its granted permissions
*
* @hide
+ * @deprecated use {@link UriGrantsManager#clearGrantedUriPermissions(String)} instead.
*/
+ @Deprecated
public void clearGrantedUriPermissions(String packageName) {
- try {
- getService().clearGrantedUriPermissions(packageName,
- mContext.getUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ ((UriGrantsManager) mContext.getSystemService(Context.URI_GRANTS_SERVICE))
+ .clearGrantedUriPermissions(packageName);
}
/**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 2e4404c..c895978 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -50,13 +50,6 @@
public static final int ALLOW_FULL_ONLY = 2;
/**
- * Grant Uri permissions from one app to another. This method only extends
- * permission grants if {@code callingUid} has permission to them.
- */
- public abstract void grantUriPermissionFromIntent(int callingUid, String targetPkg,
- Intent intent, int targetUserId);
-
- /**
* Verify that calling app has access to the given provider.
*/
public abstract String checkContentProviderAccess(String authority, int userId);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 19d7c83..285f83b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -243,12 +243,6 @@
boolean isTopActivityImmersive();
void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message);
String getProviderMimeType(in Uri uri, int userId);
- IBinder newUriPermissionOwner(in String name);
- void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg,
- in Uri uri, int mode, int sourceUserId, int targetUserId);
- void revokeUriPermissionFromOwner(in IBinder owner, in Uri uri, int mode, int userId);
- int checkGrantUriPermission(int callingUid, in String targetPkg, in Uri uri,
- int modeFlags, int userId);
// Cause the specified process to dump the specified heap.
boolean dumpHeap(in String process, int userId, boolean managed, boolean mallocInfo,
boolean runGc, in String path, in ParcelFileDescriptor fd,
@@ -363,9 +357,6 @@
ActivityManager.StackInfo getFocusedStackInfo();
void restart();
void performIdleMaintenance();
- void takePersistableUriPermission(in Uri uri, int modeFlags, String toPackage, int userId);
- void releasePersistableUriPermission(in Uri uri, int modeFlags, String toPackage, int userId);
- ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming);
void appNotRespondingViaProvider(in IBinder connection);
Rect getTaskBounds(int taskId);
boolean setProcessMemoryTrimLevel(in String process, int uid, int level);
@@ -441,12 +432,6 @@
void resizeDockedStack(in Rect dockedBounds, in Rect tempDockedTaskBounds,
in Rect tempDockedTaskInsetBounds,
in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
- // Gets the URI permissions granted to an arbitrary package (or all packages if null)
- // NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
- // granted to another packages (instead of those granted to it).
- ParceledListSlice getGrantedUriPermissions(in String packageName, int userId);
- // Clears the URI permissions granted to an arbitrary package.
- void clearGrantedUriPermissions(in String packageName, int userId);
boolean isAppForeground(int uid);
void removeStack(int stackId);
void makePackageIdle(String packageName, int userId);
diff --git a/core/java/android/app/IUriGrantsManager.aidl b/core/java/android/app/IUriGrantsManager.aidl
new file mode 100644
index 0000000..928c627
--- /dev/null
+++ b/core/java/android/app/IUriGrantsManager.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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 android.app;
+
+import android.content.pm.ParceledListSlice;
+import android.net.Uri;
+import android.os.IBinder;
+
+/**
+ * Interface for managing an app's permission to access a particular URI.
+ * {@hide}
+ */
+interface IUriGrantsManager {
+ void takePersistableUriPermission(in Uri uri, int modeFlags, String toPackage, int userId);
+ void releasePersistableUriPermission(in Uri uri, int modeFlags, String toPackage, int userId);
+ void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg,
+ in Uri uri, int mode, int sourceUserId, int targetUserId);
+ /**
+ * Gets the URI permissions granted to an arbitrary package (or all packages if null)
+ * NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
+ * granted to another packages (instead of those granted to it).
+ */
+ ParceledListSlice getGrantedUriPermissions(in String packageName, int userId);
+ /** Clears the URI permissions granted to an arbitrary package. */
+ void clearGrantedUriPermissions(in String packageName, int userId);
+ ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming);
+}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index b432baa..003f364 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -226,6 +226,14 @@
ctx.getOuterContext(), ctx.mMainThread.getHandler());
}});
+ registerService(Context.URI_GRANTS_SERVICE, UriGrantsManager.class,
+ new CachedServiceFetcher<UriGrantsManager>() {
+ @Override
+ public UriGrantsManager createService(ContextImpl ctx) {
+ return new UriGrantsManager(
+ ctx.getOuterContext(), ctx.mMainThread.getHandler());
+ }});
+
registerService(Context.ALARM_SERVICE, AlarmManager.class,
new CachedServiceFetcher<AlarmManager>() {
@Override
diff --git a/core/java/android/app/UriGrantsManager.java b/core/java/android/app/UriGrantsManager.java
new file mode 100644
index 0000000..5096f73
--- /dev/null
+++ b/core/java/android/app/UriGrantsManager.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 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 android.app;
+
+import android.annotation.Nullable;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Singleton;
+
+/**
+ * Class for managing an app's permission to access a particular {@link android.net.Uri}.
+ *
+ * @hide
+ */
+@SystemService(Context.URI_GRANTS_SERVICE)
+public class UriGrantsManager {
+
+ private final Context mContext;
+
+ UriGrantsManager(Context context, Handler handler) {
+ mContext = context;
+ }
+
+ /** @hide */
+ public static IUriGrantsManager getService() {
+ return IUriGrantsManagerSingleton.get();
+ }
+
+ private static final Singleton<IUriGrantsManager> IUriGrantsManagerSingleton =
+ new Singleton<IUriGrantsManager>() {
+ @Override
+ protected IUriGrantsManager create() {
+ final IBinder b = ServiceManager.getService(Context.URI_GRANTS_SERVICE);
+ return IUriGrantsManager.Stub.asInterface(b);
+ }
+ };
+
+ /**
+ * Permits an application to clear the persistent URI permissions granted to another.
+ *
+ * <p>Typically called by Settings, requires {@code CLEAR_APP_GRANTED_URI_PERMISSIONS}.
+ *
+ * @param packageName application to clear its granted permissions
+ *
+ * @hide
+ */
+ public void clearGrantedUriPermissions(String packageName) {
+ try {
+ getService().clearGrantedUriPermissions(packageName, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Permits an application to get the persistent URI permissions granted to another.
+ *
+ * <p>Typically called by Settings or DocumentsUI, requires
+ * {@code GET_APP_GRANTED_URI_PERMISSIONS}.
+ *
+ * @param packageName application to look for the granted permissions, or {@code null} to get
+ * granted permissions for all applications
+ * @return list of granted URI permissions
+ *
+ * @hide
+ */
+ public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+ @Nullable String packageName) {
+ try {
+ @SuppressWarnings("unchecked")
+ final ParceledListSlice<GrantedUriPermission> castedList = getService()
+ .getGrantedUriPermissions(packageName, mContext.getUserId());
+ return castedList;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f923738..0ca7dae 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -26,6 +26,7 @@
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
+import android.app.UriGrantsManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
@@ -2143,7 +2144,7 @@
@Intent.AccessUriMode int modeFlags) {
Preconditions.checkNotNull(uri, "uri");
try {
- ActivityManager.getService().takePersistableUriPermission(
+ UriGrantsManager.getService().takePersistableUriPermission(
ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
resolveUserId(uri));
} catch (RemoteException e) {
@@ -2159,7 +2160,7 @@
Preconditions.checkNotNull(toPackage, "toPackage");
Preconditions.checkNotNull(uri, "uri");
try {
- ActivityManager.getService().takePersistableUriPermission(
+ UriGrantsManager.getService().takePersistableUriPermission(
ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage,
resolveUserId(uri));
} catch (RemoteException e) {
@@ -2179,7 +2180,7 @@
@Intent.AccessUriMode int modeFlags) {
Preconditions.checkNotNull(uri, "uri");
try {
- ActivityManager.getService().releasePersistableUriPermission(
+ UriGrantsManager.getService().releasePersistableUriPermission(
ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
resolveUserId(uri));
} catch (RemoteException e) {
@@ -2199,7 +2200,7 @@
*/
public @NonNull List<UriPermission> getPersistedUriPermissions() {
try {
- return ActivityManager.getService()
+ return UriGrantsManager.getService()
.getPersistedUriPermissions(mPackageName, true).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2215,7 +2216,7 @@
*/
public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
try {
- return ActivityManager.getService()
+ return UriGrantsManager.getService()
.getPersistedUriPermissions(mPackageName, false).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c515bce..6abe777 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3340,6 +3340,16 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.app.UriGrantsManager} for interacting with the global system state.
+ *
+ * @see #getSystemService(String)
+ * @see android.app.UriGrantsManager
+ * @hide
+ */
+ public static final String URI_GRANTS_SERVICE = "uri_grants";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.app.AlarmManager} for receiving intents at a
* time of your choosing.
*
diff --git a/services/core/java/com/android/server/InputContentUriTokenHandler.java b/services/core/java/com/android/server/InputContentUriTokenHandler.java
index 57cdc94..6338b2f 100644
--- a/services/core/java/com/android/server/InputContentUriTokenHandler.java
+++ b/services/core/java/com/android/server/InputContentUriTokenHandler.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.UriGrantsManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Binder;
@@ -27,6 +28,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.server.uri.UriGrantsManagerInternal;
final class InputContentUriTokenHandler extends IInputContentUriToken.Stub {
@@ -63,12 +65,8 @@
return;
}
- try {
- mPermissionOwnerToken = ActivityManager.getService()
- .newUriPermissionOwner("InputContentUriTokenHandler");
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ mPermissionOwnerToken = LocalServices.getService(UriGrantsManagerInternal.class)
+ .newUriPermissionOwner("InputContentUriTokenHandler");
doTakeLocked(mPermissionOwnerToken);
}
@@ -78,7 +76,7 @@
long origId = Binder.clearCallingIdentity();
try {
try {
- ActivityManager.getService().grantUriPermissionFromOwner(
+ UriGrantsManager.getService().grantUriPermissionFromOwner(
permissionOwner, mSourceUid, mTargetPackage, mUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId, mTargetUserId);
} catch (RemoteException e) {
@@ -96,11 +94,9 @@
return;
}
try {
- ActivityManager.getService().revokeUriPermissionFromOwner(
- mPermissionOwnerToken, mUri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ LocalServices.getService(UriGrantsManagerInternal.class)
+ .revokeUriPermissionFromOwner(mPermissionOwnerToken, mUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId);
} finally {
mPermissionOwnerToken = null;
}
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 8402087..f15cd2ad 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -42,6 +42,7 @@
import android.util.Slog;
import com.android.internal.telephony.IMms;
+import com.android.server.uri.UriGrantsManagerInternal;
import java.util.List;
@@ -512,7 +513,7 @@
long token = Binder.clearCallingIdentity();
try {
- LocalServices.getService(ActivityManagerInternal.class)
+ LocalServices.getService(UriGrantsManagerInternal.class)
.grantUriPermissionFromIntent(callingUid, PHONE_PACKAGE_NAME,
grantIntent, UserHandle.USER_SYSTEM);
@@ -523,7 +524,7 @@
List<String> carrierPackages = telephonyManager.getCarrierPackageNamesForIntent(
intent);
if (carrierPackages != null && carrierPackages.size() == 1) {
- LocalServices.getService(ActivityManagerInternal.class)
+ LocalServices.getService(UriGrantsManagerInternal.class)
.grantUriPermissionFromIntent(callingUid, carrierPackages.get(0),
grantIntent, UserHandle.USER_SYSTEM);
}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 63584d9..c5b4966 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -18,10 +18,12 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.os.Environment;
import android.os.SystemClock;
import android.os.Trace;
import android.util.Slog;
+import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
@@ -36,6 +38,7 @@
private static final String TAG = "SystemServiceManager";
private static final int SERVICE_CALL_WARN_TIME_MS = 50;
+ private static File sSystemDir;
private final Context mContext;
private boolean mSafeMode;
private boolean mRuntimeRestarted;
@@ -318,6 +321,22 @@
}
/**
+ * Ensures that the system directory exist creating one if needed.
+ * @deprecated Use {@link Environment#getDataSystemCeDirectory()}
+ * or {@link Environment#getDataSystemDeDirectory()} instead.
+ * @return The system directory.
+ */
+ @Deprecated
+ public static File ensureSystemDir() {
+ if (sSystemDir == null) {
+ File dataDir = Environment.getDataDirectory();
+ sSystemDir = new File(dataDir, "system");
+ sSystemDir.mkdirs();
+ }
+ return sSystemDir;
+ }
+
+ /**
* Outputs the state of this manager to the System log.
*/
public void dump() {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 9c55de7..e9f4805 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -65,7 +65,6 @@
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
-import com.android.server.am.ActivityManagerService.NeededUriGrants;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -96,6 +95,7 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.webkit.WebViewZygote;
+import com.android.server.uri.NeededUriGrants;
public final class ActiveServices {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
@@ -512,7 +512,7 @@
fgRequired = false;
}
- NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
+ NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
// If permissions need a review before any of the app components can run,
@@ -2581,7 +2581,7 @@
r.deliveredStarts.add(si);
si.deliveryCount++;
if (si.neededGrants != null) {
- mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
+ mAm.mUgmInternal.grantUriPermissionUncheckedFromIntent(si.neededGrants,
si.getUriPermissionsLocked());
}
mAm.grantEphemeralAccessLocked(r.userId, si.intent,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e1ebbec..3a4d777 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -91,13 +91,9 @@
import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
-import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
@@ -122,7 +118,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
@@ -148,8 +143,6 @@
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.MemoryStatUtil.hasMemcg;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
import android.Manifest.permission;
@@ -172,7 +165,6 @@
import android.app.BroadcastOptions;
import android.app.ContentProviderHolder;
import android.app.Dialog;
-import android.app.GrantedUriPermission;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IApplicationThread;
@@ -199,7 +191,6 @@
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
-import android.content.ClipData;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -248,7 +239,6 @@
import android.os.Bundle;
import android.os.Debug;
import android.os.DropBoxManager;
-import android.os.Environment;
import android.os.FactoryTest;
import android.os.FileUtils;
import android.os.Handler;
@@ -281,14 +271,12 @@
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
-import android.provider.Downloads;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.style.SuggestionSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.DebugUtils;
import android.util.EventLog;
import android.util.Log;
@@ -301,7 +289,6 @@
import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.TimingsTraceLog;
-import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
import android.view.Gravity;
@@ -311,8 +298,8 @@
import android.view.WindowManager;
import android.view.autofill.AutofillManagerInternal;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
+import com.android.server.uri.GrantUri;
+import com.android.server.uri.UriGrantsManagerInternal;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -337,7 +324,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.MemInfoReader;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.QuadFunction;
@@ -372,14 +358,9 @@
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerService;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
@@ -389,7 +370,6 @@
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
-import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -412,7 +392,6 @@
import java.util.function.BiFunction;
import dalvik.system.VMRuntime;
-import libcore.io.IoUtils;
import libcore.util.EmptyArray;
public class ActivityManagerService extends IActivityManager.Stub
@@ -495,9 +474,6 @@
// Must be kept in sync with Am.
private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
- // Maximum number of persisted Uri grants a package is allowed
- static final int MAX_PERSISTED_URI_GRANTS = 128;
-
static final int MY_PID = myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -956,95 +932,7 @@
* application is currently being launched and the provider will be
* removed from this list once it is published.
*/
- final ArrayList<ContentProviderRecord> mLaunchingProviders
- = new ArrayList<ContentProviderRecord>();
-
- /**
- * File storing persisted {@link #mGrantedUriPermissions}.
- */
- private final AtomicFile mGrantFile;
-
- /** XML constants used in {@link #mGrantFile} */
- private static final String TAG_URI_GRANTS = "uri-grants";
- private static final String TAG_URI_GRANT = "uri-grant";
- private static final String ATTR_USER_HANDLE = "userHandle";
- private static final String ATTR_SOURCE_USER_ID = "sourceUserId";
- private static final String ATTR_TARGET_USER_ID = "targetUserId";
- private static final String ATTR_SOURCE_PKG = "sourcePkg";
- private static final String ATTR_TARGET_PKG = "targetPkg";
- private static final String ATTR_URI = "uri";
- private static final String ATTR_MODE_FLAGS = "modeFlags";
- private static final String ATTR_CREATED_TIME = "createdTime";
- private static final String ATTR_PREFIX = "prefix";
-
- /**
- * Global set of specific {@link Uri} permissions that have been granted.
- * This optimized lookup structure maps from {@link UriPermission#targetUid}
- * to {@link UriPermission#uri} to {@link UriPermission}.
- */
- @GuardedBy("this")
- private final SparseArray<ArrayMap<GrantUri, UriPermission>>
- mGrantedUriPermissions = new SparseArray<ArrayMap<GrantUri, UriPermission>>();
-
- public static class GrantUri {
- public final int sourceUserId;
- public final Uri uri;
- public boolean prefix;
-
- public GrantUri(int sourceUserId, Uri uri, boolean prefix) {
- this.sourceUserId = sourceUserId;
- this.uri = uri;
- this.prefix = prefix;
- }
-
- @Override
- public int hashCode() {
- int hashCode = 1;
- hashCode = 31 * hashCode + sourceUserId;
- hashCode = 31 * hashCode + uri.hashCode();
- hashCode = 31 * hashCode + (prefix ? 1231 : 1237);
- return hashCode;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof GrantUri) {
- GrantUri other = (GrantUri) o;
- return uri.equals(other.uri) && (sourceUserId == other.sourceUserId)
- && prefix == other.prefix;
- }
- return false;
- }
-
- @Override
- public String toString() {
- String result = uri.toString() + " [user " + sourceUserId + "]";
- if (prefix) result += " [prefix]";
- return result;
- }
-
- public String toSafeString() {
- String result = uri.toSafeString() + " [user " + sourceUserId + "]";
- if (prefix) result += " [prefix]";
- return result;
- }
-
- public void writeToProto(ProtoOutputStream proto, long fieldId) {
- long token = proto.start(fieldId);
- proto.write(GrantUriProto.URI, uri.toString());
- proto.write(GrantUriProto.SOURCE_USER_ID, sourceUserId);
- proto.end(token);
- }
-
- public static GrantUri resolve(int defaultSourceUserHandle, Uri uri) {
- if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
- return new GrantUri(ContentProvider.getUserIdFromUri(uri, defaultSourceUserHandle),
- ContentProvider.getUriWithoutUserId(uri), false);
- } else {
- return new GrantUri(defaultSourceUserHandle, uri, false);
- }
- }
- }
+ final ArrayList<ContentProviderRecord> mLaunchingProviders = new ArrayList<>();
boolean mSystemProvidersInstalled;
@@ -1492,6 +1380,7 @@
WindowManagerService mWindowManager;
ActivityTaskManagerService mActivityTaskManager;
ActivityTaskManagerInternal mAtmInternal;
+ UriGrantsManagerInternal mUgmInternal;
final ActivityThread mSystemThread;
private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1541,7 +1430,6 @@
static final int DISPATCH_PROCESSES_CHANGED_UI_MSG = 31;
static final int DISPATCH_PROCESS_DIED_UI_MSG = 32;
static final int REPORT_MEM_USAGE_MSG = 33;
- static final int PERSIST_URI_GRANTS_MSG = 38;
static final int UPDATE_TIME_PREFERENCE_MSG = 41;
static final int FINISH_BOOTING_MSG = 45;
static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
@@ -1955,10 +1843,6 @@
thread.start();
break;
}
- case PERSIST_URI_GRANTS_MSG: {
- writeGrantedUriPermissions();
- break;
- }
case UPDATE_TIME_PREFERENCE_MSG: {
// The user's time format preference might have changed.
// For convenience we re-use the Intent extra values.
@@ -2557,7 +2441,6 @@
mBatteryStatsService = null;
mCompatModePackages = null;
mConstants = null;
- mGrantFile = null;
mHandler = null;
mHandlerThread = null;
mIntentFirewall = null;
@@ -2622,9 +2505,7 @@
mProviderMap = new ProviderMap(this);
mAppErrors = new AppErrors(mUiContext, this);
- File dataDir = Environment.getDataDirectory();
- File systemDir = new File(dataDir, "system");
- systemDir.mkdirs();
+ final File systemDir = SystemServiceManager.ensureSystemDir();
mAppWarnings = new AppWarnings(this, mUiContext, mHandler, mUiHandler, systemDir);
@@ -2641,7 +2522,7 @@
mAppOpsService = mInjector.getAppOpsService(new File(systemDir, "appops.xml"), mHandler);
- mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants");
+ mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mUserController = new UserController(this);
@@ -2730,6 +2611,7 @@
Slog.d("AppOps", "AppOpsService published");
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
mActivityTaskManager.onActivityManagerInternalAdded();
+ mUgmInternal.onActivityManagerInternalAdded();
// Wait for the synchronized block started in mProcessCpuThread,
// so that any other access to mProcessCpuTracker from main thread
// will be blocked during mProcessCpuTracker initialization.
@@ -5018,11 +4900,9 @@
// so it told us to keep those intact -- it's about to emplace app data
// that is appropriate for those bits of system state.
if (!keepState) {
- synchronized (this) {
- // Remove all permissions granted from/to this package
- removeUriPermissionsForPackageLocked(packageName, resolvedUserId, true,
- false);
- }
+ // Remove all permissions granted from/to this package
+ mUgmInternal.removeUriPermissionsForPackage(packageName, resolvedUserId,
+ true, false);
// Reset notification state
INotificationManager inm = NotificationManager.getService();
@@ -5693,7 +5573,7 @@
}
// Remove transient permissions granted from/to this package/user
- removeUriPermissionsForPackageLocked(packageName, userId, false, false);
+ mUgmInternal.removeUriPermissionsForPackage(packageName, userId, false, false);
if (doit) {
for (i = mBroadcastQueues.length - 1; i >= 0; i--) {
@@ -7184,105 +7064,6 @@
throw new SecurityException(msg);
}
- /**
- * Determine if UID is holding permissions required to access {@link Uri} in
- * the given {@link ProviderInfo}. Final permission checking is always done
- * in {@link ContentProvider}.
- */
- private final boolean checkHoldingPermissionsLocked(
- IPackageManager pm, ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "checkHoldingPermissionsLocked: uri=" + grantUri + " uid=" + uid);
- if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
- if (ActivityManager.checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
- != PERMISSION_GRANTED) {
- return false;
- }
- }
- return checkHoldingPermissionsInternalLocked(pm, pi, grantUri, uid, modeFlags, true);
- }
-
- private final boolean checkHoldingPermissionsInternalLocked(IPackageManager pm, ProviderInfo pi,
- GrantUri grantUri, int uid, final int modeFlags, boolean considerUidPermissions) {
- if (pi.applicationInfo.uid == uid) {
- return true;
- } else if (!pi.exported) {
- return false;
- }
-
- boolean readMet = (modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0;
- boolean writeMet = (modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
- try {
- // check if target holds top-level <provider> permissions
- if (!readMet && pi.readPermission != null && considerUidPermissions
- && (pm.checkUidPermission(pi.readPermission, uid) == PERMISSION_GRANTED)) {
- readMet = true;
- }
- if (!writeMet && pi.writePermission != null && considerUidPermissions
- && (pm.checkUidPermission(pi.writePermission, uid) == PERMISSION_GRANTED)) {
- writeMet = true;
- }
-
- // track if unprotected read/write is allowed; any denied
- // <path-permission> below removes this ability
- boolean allowDefaultRead = pi.readPermission == null;
- boolean allowDefaultWrite = pi.writePermission == null;
-
- // check if target holds any <path-permission> that match uri
- final PathPermission[] pps = pi.pathPermissions;
- if (pps != null) {
- final String path = grantUri.uri.getPath();
- int i = pps.length;
- while (i > 0 && (!readMet || !writeMet)) {
- i--;
- PathPermission pp = pps[i];
- if (pp.match(path)) {
- if (!readMet) {
- final String pprperm = pp.getReadPermission();
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Checking read perm for " + pprperm + " for " + pp.getPath()
- + ": match=" + pp.match(path)
- + " check=" + pm.checkUidPermission(pprperm, uid));
- if (pprperm != null) {
- if (considerUidPermissions && pm.checkUidPermission(pprperm, uid)
- == PERMISSION_GRANTED) {
- readMet = true;
- } else {
- allowDefaultRead = false;
- }
- }
- }
- if (!writeMet) {
- final String ppwperm = pp.getWritePermission();
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Checking write perm " + ppwperm + " for " + pp.getPath()
- + ": match=" + pp.match(path)
- + " check=" + pm.checkUidPermission(ppwperm, uid));
- if (ppwperm != null) {
- if (considerUidPermissions && pm.checkUidPermission(ppwperm, uid)
- == PERMISSION_GRANTED) {
- writeMet = true;
- } else {
- allowDefaultWrite = false;
- }
- }
- }
- }
- }
- }
-
- // grant unprotected <provider> read/write, if not blocked by
- // <path-permission> above
- if (allowDefaultRead) readMet = true;
- if (allowDefaultWrite) writeMet = true;
-
- } catch (RemoteException e) {
- return false;
- }
-
- return readMet && writeMet;
- }
-
public boolean isAppStartModeDisabled(int uid, String packageName) {
synchronized (this) {
return getAppStartModeLocked(uid, packageName, 0, -1, false, true, false)
@@ -7456,67 +7237,6 @@
grantEphemeralAccess(userId, intent, targetAppId, ephemeralAppId);
}
- @GuardedBy("this")
- private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
- final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
- if (targetUris != null) {
- return targetUris.get(grantUri);
- }
- return null;
- }
-
- @GuardedBy("this")
- private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
- String targetPkg, int targetUid, GrantUri grantUri) {
- ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
- if (targetUris == null) {
- targetUris = Maps.newArrayMap();
- mGrantedUriPermissions.put(targetUid, targetUris);
- }
-
- UriPermission perm = targetUris.get(grantUri);
- if (perm == null) {
- perm = new UriPermission(sourcePkg, targetPkg, targetUid, grantUri);
- targetUris.put(grantUri, perm);
- }
-
- return perm;
- }
-
- @GuardedBy("this")
- private final boolean checkUriPermissionLocked(GrantUri grantUri, int uid,
- final int modeFlags) {
- final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
- final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
- : UriPermission.STRENGTH_OWNED;
-
- // Root gets to do everything.
- if (uid == 0) {
- return true;
- }
-
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
- if (perms == null) return false;
-
- // First look for exact match
- final UriPermission exactPerm = perms.get(grantUri);
- if (exactPerm != null && exactPerm.getStrength(modeFlags) >= minStrength) {
- return true;
- }
-
- // No exact match, look for prefixes
- final int N = perms.size();
- for (int i = 0; i < N; i++) {
- final UriPermission perm = perms.valueAt(i);
- if (perm.uri.prefix && grantUri.uri.isPathPrefixMatch(perm.uri.uri)
- && perm.getStrength(modeFlags) >= minStrength) {
- return true;
- }
- }
-
- return false;
- }
-
/**
* @param uri This uri must NOT contain an embedded userId.
* @param userId The userId in which the uri is to be resolved.
@@ -7538,395 +7258,8 @@
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
- synchronized (this) {
- return checkUriPermissionLocked(new GrantUri(userId, uri, false), uid, modeFlags)
- ? PackageManager.PERMISSION_GRANTED
- : PackageManager.PERMISSION_DENIED;
- }
- }
-
- /**
- * Check if the targetPkg can be granted permission to access uri by
- * the callingUid using the given modeFlags. Throws a security exception
- * if callingUid is not allowed to do this. Returns the uid of the target
- * if the URI permission grant should be performed; returns -1 if it is not
- * needed (for example targetPkg already has permission to access the URI).
- * If you already know the uid of the target, you can supply it in
- * lastTargetUid else set that to -1.
- */
- @GuardedBy("this")
- int checkGrantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
- final int modeFlags, int lastTargetUid) {
- if (!Intent.isAccessUriMode(modeFlags)) {
- return -1;
- }
-
- if (targetPkg != null) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Checking grant " + targetPkg + " permission to " + grantUri);
- }
-
- final IPackageManager pm = AppGlobals.getPackageManager();
-
- // If this is not a content: uri, we can't do anything with it.
- if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Can't grant URI permission for non-content URI: " + grantUri);
- return -1;
- }
-
- // Bail early if system is trying to hand out permissions directly; it
- // must always grant permissions on behalf of someone explicit.
- final int callingAppId = UserHandle.getAppId(callingUid);
- if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
- if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {
- // Exempted authority for
- // 1. cropping user photos and sharing a generated license html
- // file in Settings app
- // 2. sharing a generated license html file in TvSettings app
- } else {
- Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
- + " grant to " + grantUri + "; use startActivityAsCaller() instead");
- return -1;
- }
- }
-
- final String authority = grantUri.uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId,
- MATCH_DEBUG_TRIAGED_MISSING);
- if (pi == null) {
- Slog.w(TAG, "No content provider found for permission check: " +
- grantUri.uri.toSafeString());
- return -1;
- }
-
- int targetUid = lastTargetUid;
- if (targetUid < 0 && targetPkg != null) {
- try {
- targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.getUserId(callingUid));
- if (targetUid < 0) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Can't grant URI permission no uid for: " + targetPkg);
- return -1;
- }
- } catch (RemoteException ex) {
- return -1;
- }
- }
-
- // If we're extending a persistable grant, then we always need to create
- // the grant data structure so that take/release APIs work
- if ((modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0) {
- return targetUid;
- }
-
- if (targetUid >= 0) {
- // First... does the target actually need this permission?
- if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) {
- // No need to grant the target this permission.
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Target " + targetPkg + " already has full permission to " + grantUri);
- return -1;
- }
- } else {
- // First... there is no target package, so can anyone access it?
- boolean allowed = pi.exported;
- if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
- if (pi.readPermission != null) {
- allowed = false;
- }
- }
- if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
- if (pi.writePermission != null) {
- allowed = false;
- }
- }
- if (pi.pathPermissions != null) {
- final int N = pi.pathPermissions.length;
- for (int i=0; i<N; i++) {
- if (pi.pathPermissions[i] != null
- && pi.pathPermissions[i].match(grantUri.uri.getPath())) {
- if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
- if (pi.pathPermissions[i].getReadPermission() != null) {
- allowed = false;
- }
- }
- if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
- if (pi.pathPermissions[i].getWritePermission() != null) {
- allowed = false;
- }
- }
- break;
- }
- }
- }
- if (allowed) {
- return -1;
- }
- }
-
- /* There is a special cross user grant if:
- * - The target is on another user.
- * - Apps on the current user can access the uri without any uid permissions.
- * In this case, we grant a uri permission, even if the ContentProvider does not normally
- * grant uri permissions.
- */
- boolean specialCrossUserGrant = UserHandle.getUserId(targetUid) != grantUri.sourceUserId
- && checkHoldingPermissionsInternalLocked(pm, pi, grantUri, callingUid,
- modeFlags, false /*without considering the uid permissions*/);
-
- // Second... is the provider allowing granting of URI permissions?
- if (!specialCrossUserGrant) {
- if (!pi.grantUriPermissions) {
- throw new SecurityException("Provider " + pi.packageName
- + "/" + pi.name
- + " does not allow granting of Uri permissions (uri "
- + grantUri + ")");
- }
- if (pi.uriPermissionPatterns != null) {
- final int N = pi.uriPermissionPatterns.length;
- boolean allowed = false;
- for (int i=0; i<N; i++) {
- if (pi.uriPermissionPatterns[i] != null
- && pi.uriPermissionPatterns[i].match(grantUri.uri.getPath())) {
- allowed = true;
- break;
- }
- }
- if (!allowed) {
- throw new SecurityException("Provider " + pi.packageName
- + "/" + pi.name
- + " does not allow granting of permission to path of Uri "
- + grantUri);
- }
- }
- }
-
- // Third... does the caller itself have permission to access
- // this uri?
- if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
- // Require they hold a strong enough Uri permission
- if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) {
- if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(pi.readPermission)) {
- throw new SecurityException(
- "UID " + callingUid + " does not have permission to " + grantUri
- + "; you could obtain access using ACTION_OPEN_DOCUMENT "
- + "or related APIs");
- } else {
- throw new SecurityException(
- "UID " + callingUid + " does not have permission to " + grantUri);
- }
- }
- }
- return targetUid;
- }
-
- /**
- * @param uri This uri must NOT contain an embedded userId.
- * @param userId The userId in which the uri is to be resolved.
- */
- @Override
- public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri,
- final int modeFlags, int userId) {
- enforceNotIsolatedCaller("checkGrantUriPermission");
- synchronized(this) {
- return checkGrantUriPermissionLocked(callingUid, targetPkg,
- new GrantUri(userId, uri, false), modeFlags, -1);
- }
- }
-
- @GuardedBy("this")
- void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, GrantUri grantUri,
- final int modeFlags, UriPermissionOwner owner) {
- if (!Intent.isAccessUriMode(modeFlags)) {
- return;
- }
-
- // So here we are: the caller has the assumed permission
- // to the uri, and the target doesn't. Let's now give this to
- // the target.
-
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
-
- final String authority = grantUri.uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId,
- MATCH_DEBUG_TRIAGED_MISSING);
- if (pi == null) {
- Slog.w(TAG, "No content provider found for grant: " + grantUri.toSafeString());
- return;
- }
-
- if ((modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0) {
- grantUri.prefix = true;
- }
- final UriPermission perm = findOrCreateUriPermissionLocked(
- pi.packageName, targetPkg, targetUid, grantUri);
- perm.grantModes(modeFlags, owner);
- }
-
- @GuardedBy("this")
- void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
- final int modeFlags, UriPermissionOwner owner, int targetUserId) {
- if (targetPkg == null) {
- throw new NullPointerException("targetPkg");
- }
- int targetUid;
- final IPackageManager pm = AppGlobals.getPackageManager();
- try {
- targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING, targetUserId);
- } catch (RemoteException ex) {
- return;
- }
-
- targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, modeFlags,
- targetUid);
- if (targetUid < 0) {
- return;
- }
-
- grantUriPermissionUncheckedLocked(targetUid, targetPkg, grantUri, modeFlags,
- owner);
- }
-
- static class NeededUriGrants extends ArrayList<GrantUri> {
- final String targetPkg;
- final int targetUid;
- final int flags;
-
- NeededUriGrants(String targetPkg, int targetUid, int flags) {
- this.targetPkg = targetPkg;
- this.targetUid = targetUid;
- this.flags = flags;
- }
-
- void writeToProto(ProtoOutputStream proto, long fieldId) {
- long token = proto.start(fieldId);
- proto.write(NeededUriGrantsProto.TARGET_PACKAGE, targetPkg);
- proto.write(NeededUriGrantsProto.TARGET_UID, targetUid);
- proto.write(NeededUriGrantsProto.FLAGS, flags);
-
- final int N = this.size();
- for (int i=0; i<N; i++) {
- this.get(i).writeToProto(proto, NeededUriGrantsProto.GRANTS);
- }
- proto.end(token);
- }
- }
-
- /**
- * Like checkGrantUriPermissionLocked, but takes an Intent.
- */
- @GuardedBy("this")
- NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid,
- String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Checking URI perm to data=" + (intent != null ? intent.getData() : null)
- + " clip=" + (intent != null ? intent.getClipData() : null)
- + " from " + intent + "; flags=0x"
- + Integer.toHexString(intent != null ? intent.getFlags() : 0));
-
- if (targetPkg == null) {
- throw new NullPointerException("targetPkg");
- }
-
- if (intent == null) {
- return null;
- }
- Uri data = intent.getData();
- ClipData clip = intent.getClipData();
- if (data == null && clip == null) {
- return null;
- }
- // Default userId for uris in the intent (if they don't specify it themselves)
- int contentUserHint = intent.getContentUserHint();
- if (contentUserHint == UserHandle.USER_CURRENT) {
- contentUserHint = UserHandle.getUserId(callingUid);
- }
- final IPackageManager pm = AppGlobals.getPackageManager();
- int targetUid;
- if (needed != null) {
- targetUid = needed.targetUid;
- } else {
- try {
- targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
- targetUserId);
- } catch (RemoteException ex) {
- return null;
- }
- if (targetUid < 0) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Can't grant URI permission no uid for: " + targetPkg
- + " on user " + targetUserId);
- return null;
- }
- }
- if (data != null) {
- GrantUri grantUri = GrantUri.resolve(contentUserHint, data);
- targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
- targetUid);
- if (targetUid > 0) {
- if (needed == null) {
- needed = new NeededUriGrants(targetPkg, targetUid, mode);
- }
- needed.add(grantUri);
- }
- }
- if (clip != null) {
- for (int i=0; i<clip.getItemCount(); i++) {
- Uri uri = clip.getItemAt(i).getUri();
- if (uri != null) {
- GrantUri grantUri = GrantUri.resolve(contentUserHint, uri);
- targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
- targetUid);
- if (targetUid > 0) {
- if (needed == null) {
- needed = new NeededUriGrants(targetPkg, targetUid, mode);
- }
- needed.add(grantUri);
- }
- } else {
- Intent clipIntent = clip.getItemAt(i).getIntent();
- if (clipIntent != null) {
- NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentLocked(
- callingUid, targetPkg, clipIntent, mode, needed, targetUserId);
- if (newNeeded != null) {
- needed = newNeeded;
- }
- }
- }
- }
- }
-
- return needed;
- }
-
- /**
- * Like grantUriPermissionUncheckedLocked, but takes an Intent.
- */
- @GuardedBy("this")
- void grantUriPermissionUncheckedFromIntentLocked(NeededUriGrants needed,
- UriPermissionOwner owner) {
- if (needed != null) {
- for (int i=0; i<needed.size(); i++) {
- GrantUri grantUri = needed.get(i);
- grantUriPermissionUncheckedLocked(needed.targetUid, needed.targetPkg,
- grantUri, needed.flags, owner);
- }
- }
- }
-
- @GuardedBy("this")
- void grantUriPermissionFromIntentLocked(int callingUid,
- String targetPkg, Intent intent, UriPermissionOwner owner, int targetUserId) {
- NeededUriGrants needed = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg,
- intent, intent != null ? intent.getFlags() : 0, null, targetUserId);
- if (needed == null) {
- return;
- }
-
- grantUriPermissionUncheckedFromIntentLocked(needed, owner);
+ return mUgmInternal.checkUriPermission(new GrantUri(userId, uri, false), uid, modeFlags)
+ ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
}
/**
@@ -7957,113 +7290,11 @@
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
- grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null,
+ mUgmInternal.grantUriPermission(r.uid, targetPkg, grantUri, modeFlags, null,
UserHandle.getUserId(r.uid));
}
}
- @GuardedBy("this")
- void removeUriPermissionIfNeededLocked(UriPermission perm) {
- if (perm.modeFlags == 0) {
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
- perm.targetUid);
- if (perms != null) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Removing " + perm.targetUid + " permission to " + perm.uri);
-
- perms.remove(perm.uri);
- if (perms.isEmpty()) {
- mGrantedUriPermissions.remove(perm.targetUid);
- }
- }
- }
- }
-
- @GuardedBy("this")
- private void revokeUriPermissionLocked(String targetPackage, int callingUid, GrantUri grantUri,
- final int modeFlags) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Revoking all granted permissions to " + grantUri);
-
- final IPackageManager pm = AppGlobals.getPackageManager();
- final String authority = grantUri.uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId,
- MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
- if (pi == null) {
- Slog.w(TAG, "No content provider found for permission revoke: "
- + grantUri.toSafeString());
- return;
- }
-
- // Does the caller have this permission on the URI?
- if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
- // If they don't have direct access to the URI, then revoke any
- // ownerless URI permissions that have been granted to them.
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
- if (perms != null) {
- boolean persistChanged = false;
- for (int i = perms.size()-1; i >= 0; i--) {
- final UriPermission perm = perms.valueAt(i);
- if (targetPackage != null && !targetPackage.equals(perm.targetPkg)) {
- continue;
- }
- if (perm.uri.sourceUserId == grantUri.sourceUserId
- && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Revoking non-owned " + perm.targetUid
- + " permission to " + perm.uri);
- persistChanged |= perm.revokeModes(
- modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
- if (perm.modeFlags == 0) {
- perms.removeAt(i);
- }
- }
- }
- if (perms.isEmpty()) {
- mGrantedUriPermissions.remove(callingUid);
- }
- if (persistChanged) {
- schedulePersistUriGrants();
- }
- }
- return;
- }
-
- boolean persistChanged = false;
-
- // Go through all of the permissions and remove any that match.
- for (int i = mGrantedUriPermissions.size()-1; i >= 0; i--) {
- final int targetUid = mGrantedUriPermissions.keyAt(i);
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
-
- for (int j = perms.size()-1; j >= 0; j--) {
- final UriPermission perm = perms.valueAt(j);
- if (targetPackage != null && !targetPackage.equals(perm.targetPkg)) {
- continue;
- }
- if (perm.uri.sourceUserId == grantUri.sourceUserId
- && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Revoking " + perm.targetUid + " permission to " + perm.uri);
- persistChanged |= perm.revokeModes(
- modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION,
- targetPackage == null);
- if (perm.modeFlags == 0) {
- perms.removeAt(j);
- }
- }
- }
-
- if (perms.isEmpty()) {
- mGrantedUriPermissions.removeAt(i);
- }
- }
-
- if (persistChanged) {
- schedulePersistUriGrants();
- }
- }
-
/**
* @param uri This uri must NOT contain an embedded userId.
* @param userId The userId in which the uri is to be resolved.
@@ -8097,497 +7328,11 @@
return;
}
- revokeUriPermissionLocked(targetPackage, r.uid, new GrantUri(userId, uri, false),
+ mUgmInternal.revokeUriPermission(targetPackage, r.uid, new GrantUri(userId, uri, false),
modeFlags);
}
}
- /**
- * Remove any {@link UriPermission} granted <em>from</em> or <em>to</em> the
- * given package.
- *
- * @param packageName Package name to match, or {@code null} to apply to all
- * packages.
- * @param userHandle User to match, or {@link UserHandle#USER_ALL} to apply
- * to all users.
- * @param persistable If persistable grants should be removed.
- * @param targetOnly When {@code true}, only remove permissions where the app is the target,
- * not source.
- */
- @GuardedBy("this")
- private void removeUriPermissionsForPackageLocked(
- String packageName, int userHandle, boolean persistable, boolean targetOnly) {
- if (userHandle == UserHandle.USER_ALL && packageName == null) {
- throw new IllegalArgumentException("Must narrow by either package or user");
- }
-
- boolean persistChanged = false;
-
- int N = mGrantedUriPermissions.size();
- for (int i = 0; i < N; i++) {
- final int targetUid = mGrantedUriPermissions.keyAt(i);
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
-
- // Only inspect grants matching user
- if (userHandle == UserHandle.USER_ALL
- || userHandle == UserHandle.getUserId(targetUid)) {
- for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
- final UriPermission perm = it.next();
-
- // Only inspect grants matching package
- if (packageName == null || (!targetOnly && perm.sourcePkg.equals(packageName))
- || perm.targetPkg.equals(packageName)) {
- // Hacky solution as part of fixing a security bug; ignore
- // grants associated with DownloadManager so we don't have
- // to immediately launch it to regrant the permissions
- if (Downloads.Impl.AUTHORITY.equals(perm.uri.uri.getAuthority())
- && !persistable) continue;
-
- persistChanged |= perm.revokeModes(persistable
- ? ~0 : ~Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
-
- // Only remove when no modes remain; any persisted grants
- // will keep this alive.
- if (perm.modeFlags == 0) {
- it.remove();
- }
- }
- }
-
- if (perms.isEmpty()) {
- mGrantedUriPermissions.remove(targetUid);
- N--;
- i--;
- }
- }
- }
-
- if (persistChanged) {
- schedulePersistUriGrants();
- }
- }
-
- @Override
- public IBinder newUriPermissionOwner(String name) {
- enforceNotIsolatedCaller("newUriPermissionOwner");
- synchronized(this) {
- UriPermissionOwner owner = new UriPermissionOwner(this, name);
- return owner.getExternalTokenLocked();
- }
- }
-
- /**
- * @param uri This uri must NOT contain an embedded userId.
- * @param sourceUserId The userId in which the uri is to be resolved.
- * @param targetUserId The userId of the app that receives the grant.
- */
- @Override
- public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
- final int modeFlags, int sourceUserId, int targetUserId) {
- targetUserId = mUserController.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), targetUserId, false, ALLOW_FULL_ONLY,
- "grantUriPermissionFromOwner", null);
- synchronized(this) {
- UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
- if (owner == null) {
- throw new IllegalArgumentException("Unknown owner: " + token);
- }
- if (fromUid != Binder.getCallingUid()) {
- if (Binder.getCallingUid() != myUid()) {
- // Only system code can grant URI permissions on behalf
- // of other users.
- throw new SecurityException("nice try");
- }
- }
- if (targetPkg == null) {
- throw new IllegalArgumentException("null target");
- }
- if (uri == null) {
- throw new IllegalArgumentException("null uri");
- }
-
- grantUriPermissionLocked(fromUid, targetPkg, new GrantUri(sourceUserId, uri, false),
- modeFlags, owner, targetUserId);
- }
- }
-
- /**
- * @param uri This uri must NOT contain an embedded userId.
- * @param userId The userId in which the uri is to be resolved.
- */
- @Override
- public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) {
- synchronized(this) {
- UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
- if (owner == null) {
- throw new IllegalArgumentException("Unknown owner: " + token);
- }
-
- if (uri == null) {
- owner.removeUriPermissionsLocked(mode);
- } else {
- final boolean prefix = (mode & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0;
- owner.removeUriPermissionLocked(new GrantUri(userId, uri, prefix), mode);
- }
- }
- }
-
- private void schedulePersistUriGrants() {
- if (!mHandler.hasMessages(PERSIST_URI_GRANTS_MSG)) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG),
- 10 * DateUtils.SECOND_IN_MILLIS);
- }
- }
-
- private void writeGrantedUriPermissions() {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "writeGrantedUriPermissions()");
-
- final long startTime = SystemClock.uptimeMillis();
-
- // Snapshot permissions so we can persist without lock
- ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
- synchronized (this) {
- final int size = mGrantedUriPermissions.size();
- for (int i = 0; i < size; i++) {
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
- for (UriPermission perm : perms.values()) {
- if (perm.persistedModeFlags != 0) {
- persist.add(perm.snapshot());
- }
- }
- }
- }
-
- FileOutputStream fos = null;
- try {
- fos = mGrantFile.startWrite(startTime);
-
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(fos, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
- out.startTag(null, TAG_URI_GRANTS);
- for (UriPermission.Snapshot perm : persist) {
- out.startTag(null, TAG_URI_GRANT);
- writeIntAttribute(out, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId);
- writeIntAttribute(out, ATTR_TARGET_USER_ID, perm.targetUserId);
- out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
- out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
- out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri));
- writeBooleanAttribute(out, ATTR_PREFIX, perm.uri.prefix);
- writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
- writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
- out.endTag(null, TAG_URI_GRANT);
- }
- out.endTag(null, TAG_URI_GRANTS);
- out.endDocument();
-
- mGrantFile.finishWrite(fos);
- } catch (IOException e) {
- if (fos != null) {
- mGrantFile.failWrite(fos);
- }
- }
- }
-
- @GuardedBy("this")
- private void readGrantedUriPermissionsLocked() {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "readGrantedUriPermissions()");
-
- final long now = System.currentTimeMillis();
-
- FileInputStream fis = null;
- try {
- fis = mGrantFile.openRead();
- final XmlPullParser in = Xml.newPullParser();
- in.setInput(fis, StandardCharsets.UTF_8.name());
-
- int type;
- while ((type = in.next()) != END_DOCUMENT) {
- final String tag = in.getName();
- if (type == START_TAG) {
- if (TAG_URI_GRANT.equals(tag)) {
- final int sourceUserId;
- final int targetUserId;
- final int userHandle = readIntAttribute(in,
- ATTR_USER_HANDLE, UserHandle.USER_NULL);
- if (userHandle != UserHandle.USER_NULL) {
- // For backwards compatibility.
- sourceUserId = userHandle;
- targetUserId = userHandle;
- } else {
- sourceUserId = readIntAttribute(in, ATTR_SOURCE_USER_ID);
- targetUserId = readIntAttribute(in, ATTR_TARGET_USER_ID);
- }
- final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
- final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
- final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
- final boolean prefix = readBooleanAttribute(in, ATTR_PREFIX);
- final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
- final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
-
- // Sanity check that provider still belongs to source package
- // Both direct boot aware and unaware packages are fine as we
- // will do filtering at query time to avoid multiple parsing.
- final ProviderInfo pi = getProviderInfoLocked(
- uri.getAuthority(), sourceUserId, MATCH_DIRECT_BOOT_AWARE
- | MATCH_DIRECT_BOOT_UNAWARE);
- if (pi != null && sourcePkg.equals(pi.packageName)) {
- int targetUid = -1;
- try {
- targetUid = AppGlobals.getPackageManager().getPackageUid(
- targetPkg, MATCH_UNINSTALLED_PACKAGES, targetUserId);
- } catch (RemoteException e) {
- }
- if (targetUid != -1) {
- final UriPermission perm = findOrCreateUriPermissionLocked(
- sourcePkg, targetPkg, targetUid,
- new GrantUri(sourceUserId, uri, prefix));
- perm.initPersistedModes(modeFlags, createdTime);
- }
- } else {
- Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg
- + " but instead found " + pi);
- }
- }
- }
- }
- } catch (FileNotFoundException e) {
- // Missing grants is okay
- } catch (IOException e) {
- Slog.wtf(TAG, "Failed reading Uri grants", e);
- } catch (XmlPullParserException e) {
- Slog.wtf(TAG, "Failed reading Uri grants", e);
- } finally {
- IoUtils.closeQuietly(fis);
- }
- }
-
- /**
- * @param uri This uri must NOT contain an embedded userId.
- * @param toPackage Name of package whose uri is being granted to (if {@code null}, uses
- * calling uid)
- * @param userId The userId in which the uri is to be resolved.
- */
- @Override
- public void takePersistableUriPermission(Uri uri, final int modeFlags,
- @Nullable String toPackage, int userId) {
- final int uid;
- if (toPackage != null) {
- enforceCallingPermission(android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS,
- "takePersistableUriPermission");
- uid = mPackageManagerInt.getPackageUid(toPackage, 0, userId);
- } else {
- enforceNotIsolatedCaller("takePersistableUriPermission");
- uid = Binder.getCallingUid();
- }
-
- Preconditions.checkFlagsArgument(modeFlags,
- Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-
- synchronized (this) {
- boolean persistChanged = false;
- GrantUri grantUri = new GrantUri(userId, uri, false);
-
- UriPermission exactPerm = findUriPermissionLocked(uid, grantUri);
- UriPermission prefixPerm = findUriPermissionLocked(uid,
- new GrantUri(userId, uri, true));
-
- final boolean exactValid = (exactPerm != null)
- && ((modeFlags & exactPerm.persistableModeFlags) == modeFlags);
- final boolean prefixValid = (prefixPerm != null)
- && ((modeFlags & prefixPerm.persistableModeFlags) == modeFlags);
-
- if (!(exactValid || prefixValid)) {
- throw new SecurityException("No persistable permission grants found for UID "
- + uid + " and Uri " + grantUri.toSafeString());
- }
-
- if (exactValid) {
- persistChanged |= exactPerm.takePersistableModes(modeFlags);
- }
- if (prefixValid) {
- persistChanged |= prefixPerm.takePersistableModes(modeFlags);
- }
-
- persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
-
- if (persistChanged) {
- schedulePersistUriGrants();
- }
- }
- }
-
- /**
- * @param uri This uri must NOT contain an embedded userId.
- * @param toPackage Name of the target package whose uri is being released (if {@code null},
- * uses calling uid)
- * @param userId The userId in which the uri is to be resolved.
- */
- @Override
- public void releasePersistableUriPermission(Uri uri, final int modeFlags,
- @Nullable String toPackage, int userId) {
-
- final int uid;
- if (toPackage != null) {
- enforceCallingPermission(android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS,
- "releasePersistableUriPermission");
- uid = mPackageManagerInt.getPackageUid(toPackage, 0, userId);
- } else {
- enforceNotIsolatedCaller("releasePersistableUriPermission");
- uid = Binder.getCallingUid();
- }
-
- Preconditions.checkFlagsArgument(modeFlags,
- Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-
- synchronized (this) {
- boolean persistChanged = false;
-
- UriPermission exactPerm = findUriPermissionLocked(uid,
- new GrantUri(userId, uri, false));
- UriPermission prefixPerm = findUriPermissionLocked(uid,
- new GrantUri(userId, uri, true));
- if (exactPerm == null && prefixPerm == null && toPackage == null) {
- throw new SecurityException("No permission grants found for UID " + uid
- + " and Uri " + uri.toSafeString());
- }
-
- if (exactPerm != null) {
- persistChanged |= exactPerm.releasePersistableModes(modeFlags);
- removeUriPermissionIfNeededLocked(exactPerm);
- }
- if (prefixPerm != null) {
- persistChanged |= prefixPerm.releasePersistableModes(modeFlags);
- removeUriPermissionIfNeededLocked(prefixPerm);
- }
-
- if (persistChanged) {
- schedulePersistUriGrants();
- }
- }
- }
-
- /**
- * Prune any older {@link UriPermission} for the given UID until outstanding
- * persisted grants are below {@link #MAX_PERSISTED_URI_GRANTS}.
- *
- * @return if any mutations occured that require persisting.
- */
- @GuardedBy("this")
- private boolean maybePrunePersistedUriGrantsLocked(int uid) {
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
- if (perms == null) return false;
- if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
-
- final ArrayList<UriPermission> persisted = Lists.newArrayList();
- for (UriPermission perm : perms.values()) {
- if (perm.persistedModeFlags != 0) {
- persisted.add(perm);
- }
- }
-
- final int trimCount = persisted.size() - MAX_PERSISTED_URI_GRANTS;
- if (trimCount <= 0) return false;
-
- Collections.sort(persisted, new UriPermission.PersistedTimeComparator());
- for (int i = 0; i < trimCount; i++) {
- final UriPermission perm = persisted.get(i);
-
- if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
- "Trimming grant created at " + perm.persistedCreateTime);
-
- perm.releasePersistableModes(~0);
- removeUriPermissionIfNeededLocked(perm);
- }
-
- return true;
- }
-
- @Override
- public ParceledListSlice<android.content.UriPermission> getPersistedUriPermissions(
- String packageName, boolean incoming) {
- enforceNotIsolatedCaller("getPersistedUriPermissions");
- Preconditions.checkNotNull(packageName, "packageName");
-
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- final IPackageManager pm = AppGlobals.getPackageManager();
- try {
- final int packageUid = pm.getPackageUid(packageName,
- MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUserId);
- if (packageUid != callingUid) {
- throw new SecurityException(
- "Package " + packageName + " does not belong to calling UID " + callingUid);
- }
- } catch (RemoteException e) {
- throw new SecurityException("Failed to verify package name ownership");
- }
-
- final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
- synchronized (this) {
- if (incoming) {
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
- callingUid);
- if (perms == null) {
- Slog.w(TAG, "No permission grants found for " + packageName);
- } else {
- for (int j = 0; j < perms.size(); j++) {
- final UriPermission perm = perms.valueAt(j);
- if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
- result.add(perm.buildPersistedPublicApiObject());
- }
- }
- }
- } else {
- final int size = mGrantedUriPermissions.size();
- for (int i = 0; i < size; i++) {
- final ArrayMap<GrantUri, UriPermission> perms =
- mGrantedUriPermissions.valueAt(i);
- for (int j = 0; j < perms.size(); j++) {
- final UriPermission perm = perms.valueAt(j);
- if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
- result.add(perm.buildPersistedPublicApiObject());
- }
- }
- }
- }
- }
- return new ParceledListSlice<android.content.UriPermission>(result);
- }
-
- @Override
- public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
- @Nullable String packageName, int userId) {
- enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
- "getGrantedUriPermissions");
-
- final List<GrantedUriPermission> result = new ArrayList<>();
- synchronized (this) {
- final int size = mGrantedUriPermissions.size();
- for (int i = 0; i < size; i++) {
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
- for (int j = 0; j < perms.size(); j++) {
- final UriPermission perm = perms.valueAt(j);
- if ((packageName == null || packageName.equals(perm.targetPkg))
- && perm.targetUserId == userId
- && perm.persistedModeFlags != 0) {
- result.add(perm.buildGrantedUriPermission());
- }
- }
- }
- }
- return new ParceledListSlice<>(result);
- }
-
- @Override
- public void clearGrantedUriPermissions(String packageName, int userId) {
- enforceCallingPermission(android.Manifest.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS,
- "clearGrantedUriPermissions");
- synchronized(this) {
- removeUriPermissionsForPackageLocked(packageName, userId, true, true);
- }
- }
-
@Override
public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
synchronized (this) {
@@ -8909,7 +7654,8 @@
// Looking for cross-user grants before enforcing the typical cross-users permissions
int tmpTargetUserId = mUserController.unsafeConvertIncomingUser(userId);
if (tmpTargetUserId != UserHandle.getUserId(callingUid)) {
- if (checkAuthorityGrants(callingUid, cpi, tmpTargetUserId, checkUser)) {
+ if (mUgmInternal.checkAuthorityGrants(
+ callingUid, cpi, tmpTargetUserId, checkUser)) {
return null;
}
checkedGrants = true;
@@ -8955,7 +7701,8 @@
}
}
}
- if (!checkedGrants && checkAuthorityGrants(callingUid, cpi, userId, checkUser)) {
+ if (!checkedGrants
+ && mUgmInternal.checkAuthorityGrants(callingUid, cpi, userId, checkUser)) {
return null;
}
@@ -8974,41 +7721,6 @@
return msg;
}
- /**
- * Returns if the ContentProvider has granted a uri to callingUid
- */
- boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId, boolean checkUser) {
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
- if (perms != null) {
- for (int i=perms.size()-1; i>=0; i--) {
- GrantUri grantUri = perms.keyAt(i);
- if (grantUri.sourceUserId == userId || !checkUser) {
- if (matchesProvider(grantUri.uri, cpi)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- /**
- * Returns true if the uri authority is one of the authorities specified in the provider.
- */
- boolean matchesProvider(Uri uri, ProviderInfo cpi) {
- String uriAuth = uri.getAuthority();
- String cpiAuth = cpi.authority;
- if (cpiAuth.indexOf(';') == -1) {
- return cpiAuth.equals(uriAuth);
- }
- String[] cpiAuths = cpiAuth.split(";");
- int length = cpiAuths.length;
- for (int i = 0; i < length; i++) {
- if (cpiAuths[i].equals(uriAuth)) return true;
- }
- return false;
- }
-
ContentProviderConnection incProviderCountLocked(ProcessRecord r,
final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
String callingTag, boolean stable) {
@@ -11492,9 +10204,7 @@
retrieveSettings();
final int currentUserId = mUserController.getCurrentUserId();
- synchronized (this) {
- readGrantedUriPermissionsLocked();
- }
+ mUgmInternal.onSystemReady();
final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
if (pmi != null) {
@@ -14303,48 +13013,10 @@
@GuardedBy("this")
void dumpPermissionsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
- boolean needSep = false;
- boolean printedAnything = false;
pw.println("ACTIVITY MANAGER URI PERMISSIONS (dumpsys activity permissions)");
- if (mGrantedUriPermissions.size() > 0) {
- boolean printed = false;
- int dumpUid = -2;
- if (dumpPackage != null) {
- try {
- dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage,
- MATCH_ANY_USER, 0);
- } catch (NameNotFoundException e) {
- dumpUid = -1;
- }
- }
- for (int i=0; i<mGrantedUriPermissions.size(); i++) {
- int uid = mGrantedUriPermissions.keyAt(i);
- if (dumpUid >= -1 && UserHandle.getAppId(uid) != dumpUid) {
- continue;
- }
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
- if (!printed) {
- if (needSep) pw.println();
- needSep = true;
- pw.println(" Granted Uri Permissions:");
- printed = true;
- printedAnything = true;
- }
- pw.print(" * UID "); pw.print(uid); pw.println(" holds:");
- for (UriPermission perm : perms.values()) {
- pw.print(" "); pw.println(perm);
- if (dumpAll) {
- perm.dump(pw, " ");
- }
- }
- }
- }
-
- if (!printedAnything) {
- pw.println(" (nothing)");
- }
+ mUgmInternal.dump(pw, dumpAll, dumpPackage);
}
void dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
@@ -17722,8 +16394,8 @@
intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
// Remove all permissions granted from/to this package
- removeUriPermissionsForPackageLocked(ssp, userId, true,
- false);
+ mUgmInternal.removeUriPermissionsForPackage(ssp, userId,
+ true, false);
mActivityTaskManager.getRecentTasks().removeTasksByPackageName(ssp, userId);
@@ -22102,15 +20774,6 @@
@VisibleForTesting
final class LocalService extends ActivityManagerInternal {
@Override
- public void grantUriPermissionFromIntent(int callingUid, String targetPkg, Intent intent,
- int targetUserId) {
- synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.grantUriPermissionFromIntentLocked(callingUid,
- targetPkg, intent, null, targetUserId);
- }
- }
-
- @Override
public String checkContentProviderAccess(String authority, int userId) {
return ActivityManagerService.this.checkContentProviderAccess(authority, userId);
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index b17aada..68e70a9 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -186,6 +186,7 @@
import com.android.server.AttributeCache;
import com.android.server.AttributeCache.Entry;
import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.uri.UriPermissionOwner;
import com.android.server.wm.AppWindowContainerController;
import com.android.server.wm.AppWindowContainerListener;
import com.android.server.wm.ConfigurationContainer;
@@ -1376,7 +1377,7 @@
UriPermissionOwner getUriPermissionsLocked() {
if (uriPermissions == null) {
- uriPermissions = new UriPermissionOwner(service.mAm, this);
+ uriPermissions = new UriPermissionOwner(service.mUgmInternal, this);
}
return uriPermissions;
}
@@ -1428,7 +1429,7 @@
*/
final void deliverNewIntentLocked(int callingUid, Intent intent, String referrer) {
// The activity now gets access to the data associated with this Intent.
- service.mAm.grantUriPermissionFromIntentLocked(callingUid, packageName,
+ service.mUgmInternal.grantUriPermissionFromIntent(callingUid, packageName,
intent, getUriPermissionsLocked(), userId);
final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
boolean unsent = true;
@@ -1588,7 +1589,7 @@
void removeUriPermissionsLocked() {
if (uriPermissions != null) {
- uriPermissions.removeUriPermissionsLocked();
+ uriPermissions.removeUriPermissions();
uriPermissions = null;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d08784f..accb61f 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3368,7 +3368,7 @@
String resultWho, int requestCode, int resultCode, Intent data) {
if (callingUid > 0) {
- mService.mAm.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
+ mService.mUgmInternal.grantUriPermissionFromIntent(callingUid, r.packageName,
data, r.getUriPermissionsLocked(), r.userId);
}
@@ -3682,7 +3682,7 @@
}
}
if (r.info.applicationInfo.uid > 0) {
- mService.mAm.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
+ mService.mUgmInternal.grantUriPermissionFromIntent(r.info.applicationInfo.uid,
resultTo.packageName, resultData,
resultTo.getUriPermissionsLocked(), resultTo.userId);
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 0572ca9..f42c0af 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1409,7 +1409,7 @@
return result;
}
- mService.mAm.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
+ mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
mService.mAm.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 10e0182..77ad04c 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -135,6 +135,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.server.AppOpsService;
import com.android.server.pm.UserManagerService;
+import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import android.app.AppGlobals;
import android.app.IActivityController;
@@ -259,6 +260,7 @@
UiHandler mUiHandler;
ActivityManagerService mAm;
ActivityManagerInternal mAmInternal;
+ UriGrantsManagerInternal mUgmInternal;
/* Global service lock used by the package the owns this service. */
Object mGlobalLock;
ActivityStackSupervisor mStackSupervisor;
@@ -612,6 +614,7 @@
void onActivityManagerInternalAdded() {
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
}
protected ActivityStackSupervisor createStackSupervisor() {
@@ -3630,7 +3633,7 @@
throw new IllegalArgumentException("Activity does not exist; token="
+ activityToken);
}
- return r.getUriPermissionsLocked().getExternalTokenLocked();
+ return r.getUriPermissionsLocked().getExternalToken();
}
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8f43620..d8f94c9 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -44,6 +44,8 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
+import com.android.server.uri.NeededUriGrants;
+import com.android.server.uri.UriPermissionOwner;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -129,7 +131,7 @@
final int id;
final int callingId;
final Intent intent;
- final ActivityManagerService.NeededUriGrants neededGrants;
+ final NeededUriGrants neededGrants;
long deliveredTime;
int deliveryCount;
int doneExecutingCount;
@@ -138,7 +140,7 @@
String stringName; // caching of toString
StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
- ActivityManagerService.NeededUriGrants _neededGrants, int _callingId) {
+ NeededUriGrants _neededGrants, int _callingId) {
sr = _sr;
taskRemoved = _taskRemoved;
id = _id;
@@ -149,14 +151,14 @@
UriPermissionOwner getUriPermissionsLocked() {
if (uriPermissions == null) {
- uriPermissions = new UriPermissionOwner(sr.ams, this);
+ uriPermissions = new UriPermissionOwner(sr.ams.mUgmInternal, this);
}
return uriPermissions;
}
void removeUriPermissionsLocked() {
if (uriPermissions != null) {
- uriPermissions.removeUriPermissionsLocked();
+ uriPermissions.removeUriPermissions();
uriPermissions = null;
}
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 5db20b0..e2ad5f5 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -21,7 +21,9 @@
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IActivityManager;
+import android.app.IUriGrantsManager;
import android.app.KeyguardManager;
+import android.app.UriGrantsManager;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ContentProvider;
@@ -48,7 +50,9 @@
import android.util.Slog;
import android.util.SparseArray;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.uri.UriGrantsManagerInternal;
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -143,6 +147,8 @@
SystemProperties.getBoolean("ro.kernel.qemu", false);
private final IActivityManager mAm;
+ private final IUriGrantsManager mUgm;
+ private final UriGrantsManagerInternal mUgmInternal;
private final IUserManager mUm;
private final PackageManager mPm;
private final AppOpsManager mAppOps;
@@ -159,15 +165,12 @@
super(context);
mAm = ActivityManager.getService();
+ mUgm = UriGrantsManager.getService();
+ mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mPm = getContext().getPackageManager();
mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
- IBinder permOwner = null;
- try {
- permOwner = mAm.newUriPermissionOwner("clipboard");
- } catch (RemoteException e) {
- Slog.w("clipboard", "AM dead", e);
- }
+ final IBinder permOwner = mUgmInternal.newUriPermissionOwner("clipboard");
mPermissionOwner = permOwner;
if (IS_EMULATOR) {
mHostClipboardMonitor = new HostClipboardMonitor(
@@ -497,12 +500,10 @@
final long ident = Binder.clearCallingIdentity();
try {
// This will throw SecurityException if caller can't grant
- mAm.checkGrantUriPermission(sourceUid, null,
+ mUgmInternal.checkGrantUriPermission(sourceUid, null,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,
ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
- } catch (RemoteException ignored) {
- // Ignored because we're in same process
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -531,7 +532,7 @@
final long ident = Binder.clearCallingIdentity();
try {
- mAm.grantUriPermissionFromOwner(mPermissionOwner, sourceUid, targetPkg,
+ mUgm.grantUriPermissionFromOwner(mPermissionOwner, sourceUid, targetPkg,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,
ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
@@ -588,12 +589,10 @@
final long ident = Binder.clearCallingIdentity();
try {
- mAm.revokeUriPermissionFromOwner(mPermissionOwner,
+ mUgmInternal.revokeUriPermissionFromOwner(mPermissionOwner,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,
ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
- } catch (RemoteException ignored) {
- // Ignored because we're in same process
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/job/GrantedUriPermissions.java b/services/core/java/com/android/server/job/GrantedUriPermissions.java
index 8fecb8f..005b189 100644
--- a/services/core/java/com/android/server/job/GrantedUriPermissions.java
+++ b/services/core/java/com/android/server/job/GrantedUriPermissions.java
@@ -17,6 +17,7 @@
package com.android.server.job;
import android.app.IActivityManager;
+import android.app.UriGrantsManager;
import android.content.ClipData;
import android.content.ContentProvider;
import android.content.Intent;
@@ -26,6 +27,8 @@
import android.os.UserHandle;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import com.android.server.LocalServices;
+import com.android.server.uri.UriGrantsManagerInternal;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -42,16 +45,14 @@
mGrantFlags = grantFlags;
mSourceUserId = UserHandle.getUserId(uid);
mTag = tag;
- mPermissionOwner = am.newUriPermissionOwner("job: " + tag);
+ mPermissionOwner = LocalServices
+ .getService(UriGrantsManagerInternal.class).newUriPermissionOwner("job: " + tag);
}
public void revoke(IActivityManager am) {
for (int i = mUris.size()-1; i >= 0; i--) {
- try {
- am.revokeUriPermissionFromOwner(mPermissionOwner, mUris.get(i),
- mGrantFlags, mSourceUserId);
- } catch (RemoteException e) {
- }
+ LocalServices.getService(UriGrantsManagerInternal.class).revokeUriPermissionFromOwner(
+ mPermissionOwner, mUris.get(i), mGrantFlags, mSourceUserId);
}
mUris.clear();
}
@@ -119,8 +120,8 @@
if (curPerms == null) {
curPerms = new GrantedUriPermissions(am, grantFlags, sourceUid, tag);
}
- am.grantUriPermissionFromOwner(curPerms.mPermissionOwner, sourceUid, targetPackage,
- uri, grantFlags, sourceUserId, targetUserId);
+ UriGrantsManager.getService().grantUriPermissionFromOwner(curPerms.mPermissionOwner,
+ sourceUid, targetPackage, uri, grantFlags, sourceUserId, targetUserId);
curPerms.mUris.add(uri);
} catch (RemoteException e) {
Slog.e("JobScheduler", "AM dead");
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 507d0c4..5a0578f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -91,6 +91,7 @@
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
+import android.app.IUriGrantsManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -98,6 +99,7 @@
import android.app.NotificationManager.Policy;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.UriGrantsManager;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.backup.BackupManager;
@@ -204,6 +206,7 @@
import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import libcore.io.IoUtils;
@@ -318,6 +321,8 @@
private ICompanionDeviceManager mCompanionManager;
private AccessibilityManager mAccessibilityManager;
private IDeviceIdleController mDeviceIdleController;
+ private IUriGrantsManager mUgm;
+ private UriGrantsManagerInternal mUgmInternal;
final IBinder mForegroundToken = new Binder();
private WorkerHandler mHandler;
@@ -1365,7 +1370,8 @@
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
NotificationUsageStats usageStats, AtomicFile policyFile,
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
- UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm) {
+ UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
+ IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal) {
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1374,6 +1380,8 @@
mAccessibilityManager =
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
mAm = am;
+ mUgm = ugm;
+ mUgmInternal = ugmInternal;
mPackageManager = packageManager;
mPackageManagerClient = packageManagerClient;
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
@@ -1528,7 +1536,9 @@
(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
getGroupHelper(), ActivityManager.getService(),
LocalServices.getService(UsageStatsManagerInternal.class),
- LocalServices.getService(DevicePolicyManagerInternal.class));
+ LocalServices.getService(DevicePolicyManagerInternal.class),
+ UriGrantsManager.getService(),
+ LocalServices.getService(UriGrantsManagerInternal.class));
// register for various Intents
IntentFilter filter = new IntentFilter();
@@ -5620,12 +5630,8 @@
// If we have Uris to grant, but no owner yet, go create one
if (newUris != null && permissionOwner == null) {
- try {
- if (DBG) Slog.d(TAG, key + ": creating owner");
- permissionOwner = mAm.newUriPermissionOwner("NOTIF:" + key);
- } catch (RemoteException ignored) {
- // Ignored because we're in same process
- }
+ if (DBG) Slog.d(TAG, key + ": creating owner");
+ permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
}
// If we have no Uris to grant, but an existing owner, go destroy it
@@ -5633,11 +5639,9 @@
final long ident = Binder.clearCallingIdentity();
try {
if (DBG) Slog.d(TAG, key + ": destroying owner");
- mAm.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
+ mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
UserHandle.getUserId(oldRecord.getUid()));
permissionOwner = null;
- } catch (RemoteException ignored) {
- // Ignored because we're in same process
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5677,7 +5681,7 @@
final long ident = Binder.clearCallingIdentity();
try {
- mAm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
+ mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,
ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
@@ -5694,12 +5698,11 @@
final long ident = Binder.clearCallingIdentity();
try {
- mAm.revokeUriPermissionFromOwner(owner,
+ mUgmInternal.revokeUriPermissionFromOwner(
+ owner,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,
ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
- } catch (RemoteException ignored) {
- // Ignored because we're in same process
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 0154c72..f32b338 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -70,6 +70,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
+import com.android.server.uri.UriGrantsManagerInternal;
import java.io.PrintWriter;
import java.lang.reflect.Array;
@@ -96,6 +97,7 @@
private static final int MAX_LOGTAG_LENGTH = 35;
final StatusBarNotification sbn;
IActivityManager mAm;
+ UriGrantsManagerInternal mUgmInternal;
final int mTargetSdkVersion;
final int mOriginalFlags;
private final Context mContext;
@@ -182,6 +184,7 @@
mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
.getPackageTargetSdkVersion(sbn.getPackageName());
mAm = ActivityManager.getService();
+ mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mOriginalFlags = sbn.getNotification().flags;
mRankingTimeMs = calculateRankingTimeMs(0L);
mCreationTimeMs = sbn.getPostTime();
@@ -1107,7 +1110,7 @@
final long ident = Binder.clearCallingIdentity();
try {
// This will throw SecurityException if caller can't grant
- mAm.checkGrantUriPermission(sourceUid, null,
+ mUgmInternal.checkGrantUriPermission(sourceUid, null,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,
ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
@@ -1116,8 +1119,6 @@
mGrantableUris = new ArraySet<>();
}
mGrantableUris.add(uri);
- } catch (RemoteException ignored) {
- // Ignored because we're in same process
} catch (SecurityException e) {
if (!userOverriddenUri) {
if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
diff --git a/services/core/java/com/android/server/uri/GrantUri.java b/services/core/java/com/android/server/uri/GrantUri.java
new file mode 100644
index 0000000..c694264
--- /dev/null
+++ b/services/core/java/com/android/server/uri/GrantUri.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 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.server.uri;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.GrantUriProto;
+
+/** A {@link Uri} that can be granted to app an to access with the right permission. */
+public class GrantUri {
+ public final int sourceUserId;
+ public final Uri uri;
+ public boolean prefix;
+
+ public GrantUri(int sourceUserId, Uri uri, boolean prefix) {
+ this.sourceUserId = sourceUserId;
+ this.uri = uri;
+ this.prefix = prefix;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 1;
+ hashCode = 31 * hashCode + sourceUserId;
+ hashCode = 31 * hashCode + uri.hashCode();
+ hashCode = 31 * hashCode + (prefix ? 1231 : 1237);
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof GrantUri) {
+ GrantUri other = (GrantUri) o;
+ return uri.equals(other.uri) && (sourceUserId == other.sourceUserId)
+ && prefix == other.prefix;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ String result = uri.toString() + " [user " + sourceUserId + "]";
+ if (prefix) result += " [prefix]";
+ return result;
+ }
+
+ public String toSafeString() {
+ String result = uri.toSafeString() + " [user " + sourceUserId + "]";
+ if (prefix) result += " [prefix]";
+ return result;
+ }
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(GrantUriProto.URI, uri.toString());
+ proto.write(GrantUriProto.SOURCE_USER_ID, sourceUserId);
+ proto.end(token);
+ }
+
+ public static GrantUri resolve(int defaultSourceUserHandle, Uri uri) {
+ if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+ return new GrantUri(ContentProvider.getUserIdFromUri(uri, defaultSourceUserHandle),
+ ContentProvider.getUriWithoutUserId(uri), false);
+ } else {
+ return new GrantUri(defaultSourceUserHandle, uri, false);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/uri/NeededUriGrants.java b/services/core/java/com/android/server/uri/NeededUriGrants.java
new file mode 100644
index 0000000..87a2641
--- /dev/null
+++ b/services/core/java/com/android/server/uri/NeededUriGrants.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 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.server.uri;
+
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.NeededUriGrantsProto;
+
+import java.util.ArrayList;
+
+/** List of {@link GrantUri} a process needs. */
+public class NeededUriGrants extends ArrayList<GrantUri> {
+ final String targetPkg;
+ final int targetUid;
+ final int flags;
+
+ public NeededUriGrants(String targetPkg, int targetUid, int flags) {
+ this.targetPkg = targetPkg;
+ this.targetUid = targetUid;
+ this.flags = flags;
+ }
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(NeededUriGrantsProto.TARGET_PACKAGE, targetPkg);
+ proto.write(NeededUriGrantsProto.TARGET_UID, targetUid);
+ proto.write(NeededUriGrantsProto.FLAGS, flags);
+
+ final int N = this.size();
+ for (int i = 0; i < N; i++) {
+ this.get(i).writeToProto(proto, NeededUriGrantsProto.GRANTS);
+ }
+ proto.end(token);
+ }
+}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
new file mode 100644
index 0000000..2f50fcb
--- /dev/null
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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.server.uri;
+
+import android.content.Intent;
+import android.content.pm.ProviderInfo;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+/**
+ * Uri Grants local system service interface.
+ * @hide Only for use within system server
+ */
+public interface UriGrantsManagerInternal {
+ void onSystemReady();
+ void onActivityManagerInternalAdded();
+ void removeUriPermissionIfNeeded(UriPermission perm);
+ void grantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ final int modeFlags, UriPermissionOwner owner, int targetUserId);
+ void revokeUriPermission(String targetPackage, int callingUid,
+ GrantUri grantUri, final int modeFlags);
+ boolean checkUriPermission(GrantUri grantUri, int uid, final int modeFlags);
+ int checkGrantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ final int modeFlags, int lastTargetUid);
+ int checkGrantUriPermission(
+ int callingUid, String targetPkg, Uri uri, int modeFlags, int userId);
+ NeededUriGrants checkGrantUriPermissionFromIntent(int callingUid,
+ String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId);
+ /**
+ * Grant Uri permissions from one app to another. This method only extends
+ * permission grants if {@code callingUid} has permission to them.
+ */
+ void grantUriPermissionFromIntent(int callingUid,
+ String targetPkg, Intent intent, int targetUserId);
+ void grantUriPermissionFromIntent(int callingUid,
+ String targetPkg, Intent intent, UriPermissionOwner owner, int targetUserId);
+ void grantUriPermissionUncheckedFromIntent(
+ NeededUriGrants needed, UriPermissionOwner owner);
+ IBinder newUriPermissionOwner(String name);
+ /**
+ * Remove any {@link UriPermission} granted <em>from</em> or <em>to</em> the
+ * given package.
+ *
+ * @param packageName Package name to match, or {@code null} to apply to all
+ * packages.
+ * @param userHandle User to match, or {@link UserHandle#USER_ALL} to apply
+ * to all users.
+ * @param persistable If persistable grants should be removed.
+ * @param targetOnly When {@code true}, only remove permissions where the app is the target,
+ * not source.
+ */
+ void removeUriPermissionsForPackage(
+ String packageName, int userHandle, boolean persistable, boolean targetOnly);
+ /**
+ * @param uri This uri must NOT contain an embedded userId.
+ * @param userId The userId in which the uri is to be resolved.
+ */
+ void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId);
+ boolean checkAuthorityGrants(
+ int callingUid, ProviderInfo cpi, int userId, boolean checkUser);
+ void dump(PrintWriter pw, boolean dumpAll, String dumpPackage);
+}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
new file mode 100644
index 0000000..1b5ffda
--- /dev/null
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -0,0 +1,1472 @@
+/*
+ * Copyright (C) 2018 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.server.uri;
+
+import static android.Manifest.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS;
+import static android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS;
+import static android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.myUid;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
+import static com.android.server.uri.UriGrantsManagerService.H.PERSIST_URI_GRANTS_MSG;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.AppGlobals;
+import android.app.GrantedUriPermission;
+import android.app.IUriGrantsManager;
+import android.content.ClipData;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PathPermission;
+import android.content.pm.ProviderInfo;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Downloads;
+import android.text.format.DateUtils;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
+import com.android.server.IoThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import libcore.io.IoUtils;
+
+/** Manages uri grants. */
+public class UriGrantsManagerService extends IUriGrantsManager.Stub {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "UriGrantsManagerService";
+ // Maximum number of persisted Uri grants a package is allowed
+ private static final int MAX_PERSISTED_URI_GRANTS = 128;
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+ private final H mH;
+ ActivityManagerInternal mAmInternal;
+ PackageManagerInternal mPmInternal;
+
+ /** File storing persisted {@link #mGrantedUriPermissions}. */
+ private final AtomicFile mGrantFile;
+
+ /** XML constants used in {@link #mGrantFile} */
+ private static final String TAG_URI_GRANTS = "uri-grants";
+ private static final String TAG_URI_GRANT = "uri-grant";
+ private static final String ATTR_USER_HANDLE = "userHandle";
+ private static final String ATTR_SOURCE_USER_ID = "sourceUserId";
+ private static final String ATTR_TARGET_USER_ID = "targetUserId";
+ private static final String ATTR_SOURCE_PKG = "sourcePkg";
+ private static final String ATTR_TARGET_PKG = "targetPkg";
+ private static final String ATTR_URI = "uri";
+ private static final String ATTR_MODE_FLAGS = "modeFlags";
+ private static final String ATTR_CREATED_TIME = "createdTime";
+ private static final String ATTR_PREFIX = "prefix";
+
+ /**
+ * Global set of specific {@link Uri} permissions that have been granted.
+ * This optimized lookup structure maps from {@link UriPermission#targetUid}
+ * to {@link UriPermission#uri} to {@link UriPermission}.
+ */
+ private final SparseArray<ArrayMap<GrantUri, UriPermission>>
+ mGrantedUriPermissions = new SparseArray<>();
+
+ private UriGrantsManagerService(Context context) {
+ mContext = context;
+ mH = new H(IoThread.get().getLooper());
+ final File systemDir = SystemServiceManager.ensureSystemDir();
+ mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants");
+ }
+
+ private void start() {
+ LocalServices.addService(UriGrantsManagerInternal.class, new LocalService());
+ }
+
+ void onActivityManagerInternalAdded() {
+ mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mPmInternal = LocalServices.getService(PackageManagerInternal.class);
+ }
+
+ public static final class Lifecycle extends SystemService {
+ private final UriGrantsManagerService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ mService = new UriGrantsManagerService(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.URI_GRANTS_SERVICE, mService);
+ mService.start();
+ }
+
+ public UriGrantsManagerService getService() {
+ return mService;
+ }
+ }
+
+ /**
+ * @param uri This uri must NOT contain an embedded userId.
+ * @param sourceUserId The userId in which the uri is to be resolved.
+ * @param targetUserId The userId of the app that receives the grant.
+ */
+ @Override
+ public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
+ final int modeFlags, int sourceUserId, int targetUserId) {
+ targetUserId = mAmInternal.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), targetUserId, false, ALLOW_FULL_ONLY,
+ "grantUriPermissionFromOwner", null);
+ synchronized(mLock) {
+ UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+ if (owner == null) {
+ throw new IllegalArgumentException("Unknown owner: " + token);
+ }
+ if (fromUid != Binder.getCallingUid()) {
+ if (Binder.getCallingUid() != myUid()) {
+ // Only system code can grant URI permissions on behalf
+ // of other users.
+ throw new SecurityException("nice try");
+ }
+ }
+ if (targetPkg == null) {
+ throw new IllegalArgumentException("null target");
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("null uri");
+ }
+
+ grantUriPermission(fromUid, targetPkg, new GrantUri(sourceUserId, uri, false),
+ modeFlags, owner, targetUserId);
+ }
+ }
+
+ @Override
+ public ParceledListSlice<android.content.UriPermission> getPersistedUriPermissions(
+ String packageName, boolean incoming) {
+ enforceNotIsolatedCaller("getPersistedUriPermissions");
+ Preconditions.checkNotNull(packageName, "packageName");
+
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ final int packageUid = pm.getPackageUid(packageName,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUserId);
+ if (packageUid != callingUid) {
+ throw new SecurityException(
+ "Package " + packageName + " does not belong to calling UID " + callingUid);
+ }
+ } catch (RemoteException e) {
+ throw new SecurityException("Failed to verify package name ownership");
+ }
+
+ final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+ synchronized (mLock) {
+ if (incoming) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
+ callingUid);
+ if (perms == null) {
+ Slog.w(TAG, "No permission grants found for " + packageName);
+ } else {
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
+ if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
+ result.add(perm.buildPersistedPublicApiObject());
+ }
+ }
+ }
+ } else {
+ final int size = mGrantedUriPermissions.size();
+ for (int i = 0; i < size; i++) {
+ final ArrayMap<GrantUri, UriPermission> perms =
+ mGrantedUriPermissions.valueAt(i);
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
+ if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
+ result.add(perm.buildPersistedPublicApiObject());
+ }
+ }
+ }
+ }
+ }
+ return new ParceledListSlice<>(result);
+ }
+
+ @Override
+ public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+ @Nullable String packageName, int userId) {
+ mAmInternal.enforceCallingPermission(
+ GET_APP_GRANTED_URI_PERMISSIONS, "getGrantedUriPermissions");
+
+ final List<GrantedUriPermission> result = new ArrayList<>();
+ synchronized (mLock) {
+ final int size = mGrantedUriPermissions.size();
+ for (int i = 0; i < size; i++) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
+ if ((packageName == null || packageName.equals(perm.targetPkg))
+ && perm.targetUserId == userId
+ && perm.persistedModeFlags != 0) {
+ result.add(perm.buildGrantedUriPermission());
+ }
+ }
+ }
+ }
+ return new ParceledListSlice<>(result);
+ }
+
+ /**
+ * @param uri This uri must NOT contain an embedded userId.
+ * @param toPackage Name of package whose uri is being granted to (if {@code null}, uses
+ * calling uid)
+ * @param userId The userId in which the uri is to be resolved.
+ */
+ @Override
+ public void takePersistableUriPermission(Uri uri, final int modeFlags,
+ @Nullable String toPackage, int userId) {
+ final int uid;
+ if (toPackage != null) {
+ mAmInternal.enforceCallingPermission(FORCE_PERSISTABLE_URI_PERMISSIONS,
+ "takePersistableUriPermission");
+ uid = mPmInternal.getPackageUid(toPackage, 0, userId);
+ } else {
+ enforceNotIsolatedCaller("takePersistableUriPermission");
+ uid = Binder.getCallingUid();
+ }
+
+ Preconditions.checkFlagsArgument(modeFlags,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ synchronized (mLock) {
+ boolean persistChanged = false;
+ GrantUri grantUri = new GrantUri(userId, uri, false);
+
+ UriPermission exactPerm = findUriPermissionLocked(uid, grantUri);
+ UriPermission prefixPerm = findUriPermissionLocked(uid,
+ new GrantUri(userId, uri, true));
+
+ final boolean exactValid = (exactPerm != null)
+ && ((modeFlags & exactPerm.persistableModeFlags) == modeFlags);
+ final boolean prefixValid = (prefixPerm != null)
+ && ((modeFlags & prefixPerm.persistableModeFlags) == modeFlags);
+
+ if (!(exactValid || prefixValid)) {
+ throw new SecurityException("No persistable permission grants found for UID "
+ + uid + " and Uri " + grantUri.toSafeString());
+ }
+
+ if (exactValid) {
+ persistChanged |= exactPerm.takePersistableModes(modeFlags);
+ }
+ if (prefixValid) {
+ persistChanged |= prefixPerm.takePersistableModes(modeFlags);
+ }
+
+ persistChanged |= maybePrunePersistedUriGrants(uid);
+
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+ }
+
+ @Override
+ public void clearGrantedUriPermissions(String packageName, int userId) {
+ mAmInternal.enforceCallingPermission(
+ CLEAR_APP_GRANTED_URI_PERMISSIONS, "clearGrantedUriPermissions");
+ synchronized(mLock) {
+ removeUriPermissionsForPackage(packageName, userId, true, true);
+ }
+ }
+
+ /**
+ * @param uri This uri must NOT contain an embedded userId.
+ * @param toPackage Name of the target package whose uri is being released (if {@code null},
+ * uses calling uid)
+ * @param userId The userId in which the uri is to be resolved.
+ */
+ @Override
+ public void releasePersistableUriPermission(Uri uri, final int modeFlags,
+ @Nullable String toPackage, int userId) {
+
+ final int uid;
+ if (toPackage != null) {
+ mAmInternal.enforceCallingPermission(FORCE_PERSISTABLE_URI_PERMISSIONS,
+ "releasePersistableUriPermission");
+ uid = mPmInternal.getPackageUid(toPackage, 0, userId);
+ } else {
+ enforceNotIsolatedCaller("releasePersistableUriPermission");
+ uid = Binder.getCallingUid();
+ }
+
+ Preconditions.checkFlagsArgument(modeFlags,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ synchronized (mLock) {
+ boolean persistChanged = false;
+
+ UriPermission exactPerm = findUriPermissionLocked(uid,
+ new GrantUri(userId, uri, false));
+ UriPermission prefixPerm = findUriPermissionLocked(uid,
+ new GrantUri(userId, uri, true));
+ if (exactPerm == null && prefixPerm == null && toPackage == null) {
+ throw new SecurityException("No permission grants found for UID " + uid
+ + " and Uri " + uri.toSafeString());
+ }
+
+ if (exactPerm != null) {
+ persistChanged |= exactPerm.releasePersistableModes(modeFlags);
+ removeUriPermissionIfNeeded(exactPerm);
+ }
+ if (prefixPerm != null) {
+ persistChanged |= prefixPerm.releasePersistableModes(modeFlags);
+ removeUriPermissionIfNeeded(prefixPerm);
+ }
+
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+ }
+
+ /**
+ * Remove any {@link UriPermission} granted <em>from</em> or <em>to</em> the
+ * given package.
+ *
+ * @param packageName Package name to match, or {@code null} to apply to all
+ * packages.
+ * @param userHandle User to match, or {@link UserHandle#USER_ALL} to apply
+ * to all users.
+ * @param persistable If persistable grants should be removed.
+ * @param targetOnly When {@code true}, only remove permissions where the app is the target,
+ * not source.
+ */
+ void removeUriPermissionsForPackage(
+ String packageName, int userHandle, boolean persistable, boolean targetOnly) {
+ if (userHandle == UserHandle.USER_ALL && packageName == null) {
+ throw new IllegalArgumentException("Must narrow by either package or user");
+ }
+
+ boolean persistChanged = false;
+
+ int N = mGrantedUriPermissions.size();
+ for (int i = 0; i < N; i++) {
+ final int targetUid = mGrantedUriPermissions.keyAt(i);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+
+ // Only inspect grants matching user
+ if (userHandle == UserHandle.USER_ALL
+ || userHandle == UserHandle.getUserId(targetUid)) {
+ for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
+ final UriPermission perm = it.next();
+
+ // Only inspect grants matching package
+ if (packageName == null || (!targetOnly && perm.sourcePkg.equals(packageName))
+ || perm.targetPkg.equals(packageName)) {
+ // Hacky solution as part of fixing a security bug; ignore
+ // grants associated with DownloadManager so we don't have
+ // to immediately launch it to regrant the permissions
+ if (Downloads.Impl.AUTHORITY.equals(perm.uri.uri.getAuthority())
+ && !persistable) continue;
+
+ persistChanged |= perm.revokeModes(persistable
+ ? ~0 : ~Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
+
+ // Only remove when no modes remain; any persisted grants
+ // will keep this alive.
+ if (perm.modeFlags == 0) {
+ it.remove();
+ }
+ }
+ }
+
+ if (perms.isEmpty()) {
+ mGrantedUriPermissions.remove(targetUid);
+ N--;
+ i--;
+ }
+ }
+ }
+
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+
+ /** Returns if the ContentProvider has granted a uri to callingUid */
+ boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId, boolean checkUser) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+ if (perms != null) {
+ for (int i = perms.size() - 1; i >= 0; i--) {
+ GrantUri grantUri = perms.keyAt(i);
+ if (grantUri.sourceUserId == userId || !checkUser) {
+ if (matchesProvider(grantUri.uri, cpi)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /** Returns true if the uri authority is one of the authorities specified in the provider. */
+ private boolean matchesProvider(Uri uri, ProviderInfo cpi) {
+ String uriAuth = uri.getAuthority();
+ String cpiAuth = cpi.authority;
+ if (cpiAuth.indexOf(';') == -1) {
+ return cpiAuth.equals(uriAuth);
+ }
+ String[] cpiAuths = cpiAuth.split(";");
+ int length = cpiAuths.length;
+ for (int i = 0; i < length; i++) {
+ if (cpiAuths[i].equals(uriAuth)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Prune any older {@link UriPermission} for the given UID until outstanding
+ * persisted grants are below {@link #MAX_PERSISTED_URI_GRANTS}.
+ *
+ * @return if any mutations occured that require persisting.
+ */
+ private boolean maybePrunePersistedUriGrants(int uid) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+ if (perms == null) return false;
+ if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
+
+ final ArrayList<UriPermission> persisted = Lists.newArrayList();
+ for (UriPermission perm : perms.values()) {
+ if (perm.persistedModeFlags != 0) {
+ persisted.add(perm);
+ }
+ }
+
+ final int trimCount = persisted.size() - MAX_PERSISTED_URI_GRANTS;
+ if (trimCount <= 0) return false;
+
+ Collections.sort(persisted, new UriPermission.PersistedTimeComparator());
+ for (int i = 0; i < trimCount; i++) {
+ final UriPermission perm = persisted.get(i);
+
+ if (DEBUG) Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
+
+ perm.releasePersistableModes(~0);
+ removeUriPermissionIfNeeded(perm);
+ }
+
+ return true;
+ }
+
+ /** Like checkGrantUriPermission, but takes an Intent. */
+ NeededUriGrants checkGrantUriPermissionFromIntent(int callingUid,
+ String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
+ if (DEBUG) Slog.v(TAG,
+ "Checking URI perm to data=" + (intent != null ? intent.getData() : null)
+ + " clip=" + (intent != null ? intent.getClipData() : null)
+ + " from " + intent + "; flags=0x"
+ + Integer.toHexString(intent != null ? intent.getFlags() : 0));
+
+ if (targetPkg == null) {
+ throw new NullPointerException("targetPkg");
+ }
+
+ if (intent == null) {
+ return null;
+ }
+ Uri data = intent.getData();
+ ClipData clip = intent.getClipData();
+ if (data == null && clip == null) {
+ return null;
+ }
+ // Default userId for uris in the intent (if they don't specify it themselves)
+ int contentUserHint = intent.getContentUserHint();
+ if (contentUserHint == UserHandle.USER_CURRENT) {
+ contentUserHint = UserHandle.getUserId(callingUid);
+ }
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ int targetUid;
+ if (needed != null) {
+ targetUid = needed.targetUid;
+ } else {
+ try {
+ targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING, targetUserId);
+ } catch (RemoteException ex) {
+ return null;
+ }
+ if (targetUid < 0) {
+ if (DEBUG) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg
+ + " on user " + targetUserId);
+ return null;
+ }
+ }
+ if (data != null) {
+ GrantUri grantUri = GrantUri.resolve(contentUserHint, data);
+ targetUid = checkGrantUriPermission(callingUid, targetPkg, grantUri, mode, targetUid);
+ if (targetUid > 0) {
+ if (needed == null) {
+ needed = new NeededUriGrants(targetPkg, targetUid, mode);
+ }
+ needed.add(grantUri);
+ }
+ }
+ if (clip != null) {
+ for (int i=0; i<clip.getItemCount(); i++) {
+ Uri uri = clip.getItemAt(i).getUri();
+ if (uri != null) {
+ GrantUri grantUri = GrantUri.resolve(contentUserHint, uri);
+ targetUid = checkGrantUriPermission(callingUid, targetPkg,
+ grantUri, mode, targetUid);
+ if (targetUid > 0) {
+ if (needed == null) {
+ needed = new NeededUriGrants(targetPkg, targetUid, mode);
+ }
+ needed.add(grantUri);
+ }
+ } else {
+ Intent clipIntent = clip.getItemAt(i).getIntent();
+ if (clipIntent != null) {
+ NeededUriGrants newNeeded = checkGrantUriPermissionFromIntent(
+ callingUid, targetPkg, clipIntent, mode, needed, targetUserId);
+ if (newNeeded != null) {
+ needed = newNeeded;
+ }
+ }
+ }
+ }
+ }
+
+ return needed;
+ }
+
+ void grantUriPermissionFromIntent(int callingUid,
+ String targetPkg, Intent intent, UriPermissionOwner owner, int targetUserId) {
+ NeededUriGrants needed = checkGrantUriPermissionFromIntent(callingUid, targetPkg,
+ intent, intent != null ? intent.getFlags() : 0, null, targetUserId);
+ if (needed == null) {
+ return;
+ }
+
+ grantUriPermissionUncheckedFromIntent(needed, owner);
+ }
+
+ void readGrantedUriPermissions() {
+ if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()");
+
+ final long now = System.currentTimeMillis();
+
+ FileInputStream fis = null;
+ try {
+ fis = mGrantFile.openRead();
+ final XmlPullParser in = Xml.newPullParser();
+ in.setInput(fis, StandardCharsets.UTF_8.name());
+
+ int type;
+ while ((type = in.next()) != END_DOCUMENT) {
+ final String tag = in.getName();
+ if (type == START_TAG) {
+ if (TAG_URI_GRANT.equals(tag)) {
+ final int sourceUserId;
+ final int targetUserId;
+ final int userHandle = readIntAttribute(in,
+ ATTR_USER_HANDLE, UserHandle.USER_NULL);
+ if (userHandle != UserHandle.USER_NULL) {
+ // For backwards compatibility.
+ sourceUserId = userHandle;
+ targetUserId = userHandle;
+ } else {
+ sourceUserId = readIntAttribute(in, ATTR_SOURCE_USER_ID);
+ targetUserId = readIntAttribute(in, ATTR_TARGET_USER_ID);
+ }
+ final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
+ final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
+ final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
+ final boolean prefix = readBooleanAttribute(in, ATTR_PREFIX);
+ final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
+ final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
+
+ // Sanity check that provider still belongs to source package
+ // Both direct boot aware and unaware packages are fine as we
+ // will do filtering at query time to avoid multiple parsing.
+ final ProviderInfo pi = getProviderInfo(uri.getAuthority(), sourceUserId,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+ if (pi != null && sourcePkg.equals(pi.packageName)) {
+ int targetUid = -1;
+ try {
+ targetUid = AppGlobals.getPackageManager().getPackageUid(
+ targetPkg, MATCH_UNINSTALLED_PACKAGES, targetUserId);
+ } catch (RemoteException e) {
+ }
+ if (targetUid != -1) {
+ final UriPermission perm = findOrCreateUriPermission(
+ sourcePkg, targetPkg, targetUid,
+ new GrantUri(sourceUserId, uri, prefix));
+ perm.initPersistedModes(modeFlags, createdTime);
+ }
+ } else {
+ Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg
+ + " but instead found " + pi);
+ }
+ }
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // Missing grants is okay
+ } catch (IOException e) {
+ Slog.wtf(TAG, "Failed reading Uri grants", e);
+ } catch (XmlPullParserException e) {
+ Slog.wtf(TAG, "Failed reading Uri grants", e);
+ } finally {
+ IoUtils.closeQuietly(fis);
+ }
+ }
+
+ private UriPermission findOrCreateUriPermission(String sourcePkg,
+ String targetPkg, int targetUid, GrantUri grantUri) {
+ ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+ if (targetUris == null) {
+ targetUris = Maps.newArrayMap();
+ mGrantedUriPermissions.put(targetUid, targetUris);
+ }
+
+ UriPermission perm = targetUris.get(grantUri);
+ if (perm == null) {
+ perm = new UriPermission(sourcePkg, targetPkg, targetUid, grantUri);
+ targetUris.put(grantUri, perm);
+ }
+
+ return perm;
+ }
+
+ private void grantUriPermissionUnchecked(int targetUid, String targetPkg, GrantUri grantUri,
+ final int modeFlags, UriPermissionOwner owner) {
+ if (!Intent.isAccessUriMode(modeFlags)) {
+ return;
+ }
+
+ // So here we are: the caller has the assumed permission to the uri, and the target doesn't.
+ // Let's now give this to the target.
+
+ if (DEBUG) Slog.v(TAG,
+ "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
+
+ final String authority = grantUri.uri.getAuthority();
+ final ProviderInfo pi = getProviderInfo(authority, grantUri.sourceUserId,
+ MATCH_DEBUG_TRIAGED_MISSING);
+ if (pi == null) {
+ Slog.w(TAG, "No content provider found for grant: " + grantUri.toSafeString());
+ return;
+ }
+
+ if ((modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0) {
+ grantUri.prefix = true;
+ }
+ final UriPermission perm = findOrCreateUriPermission(
+ pi.packageName, targetPkg, targetUid, grantUri);
+ perm.grantModes(modeFlags, owner);
+ }
+
+ /** Like grantUriPermissionUnchecked, but takes an Intent. */
+ void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed, UriPermissionOwner owner) {
+ if (needed == null) {
+ return;
+ }
+ for (int i=0; i<needed.size(); i++) {
+ GrantUri grantUri = needed.get(i);
+ grantUriPermissionUnchecked(needed.targetUid, needed.targetPkg,
+ grantUri, needed.flags, owner);
+ }
+ }
+
+ void grantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ final int modeFlags, UriPermissionOwner owner, int targetUserId) {
+ if (targetPkg == null) {
+ throw new NullPointerException("targetPkg");
+ }
+ int targetUid;
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING, targetUserId);
+ } catch (RemoteException ex) {
+ return;
+ }
+
+ targetUid = checkGrantUriPermission(callingUid, targetPkg, grantUri, modeFlags, targetUid);
+ if (targetUid < 0) {
+ return;
+ }
+
+ grantUriPermissionUnchecked(targetUid, targetPkg, grantUri, modeFlags, owner);
+ }
+
+ void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
+ final int modeFlags) {
+ if (DEBUG) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
+
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ final String authority = grantUri.uri.getAuthority();
+ final ProviderInfo pi = getProviderInfo(authority, grantUri.sourceUserId,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+ if (pi == null) {
+ Slog.w(TAG, "No content provider found for permission revoke: "
+ + grantUri.toSafeString());
+ return;
+ }
+
+ // Does the caller have this permission on the URI?
+ if (!checkHoldingPermissions(pm, pi, grantUri, callingUid, modeFlags)) {
+ // If they don't have direct access to the URI, then revoke any
+ // ownerless URI permissions that have been granted to them.
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+ if (perms != null) {
+ boolean persistChanged = false;
+ for (int i = perms.size()-1; i >= 0; i--) {
+ final UriPermission perm = perms.valueAt(i);
+ if (targetPackage != null && !targetPackage.equals(perm.targetPkg)) {
+ continue;
+ }
+ if (perm.uri.sourceUserId == grantUri.sourceUserId
+ && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
+ if (DEBUG) Slog.v(TAG, "Revoking non-owned "
+ + perm.targetUid + " permission to " + perm.uri);
+ persistChanged |= perm.revokeModes(
+ modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
+ if (perm.modeFlags == 0) {
+ perms.removeAt(i);
+ }
+ }
+ }
+ if (perms.isEmpty()) {
+ mGrantedUriPermissions.remove(callingUid);
+ }
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+ return;
+ }
+
+ boolean persistChanged = false;
+
+ // Go through all of the permissions and remove any that match.
+ for (int i = mGrantedUriPermissions.size()-1; i >= 0; i--) {
+ final int targetUid = mGrantedUriPermissions.keyAt(i);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+
+ for (int j = perms.size()-1; j >= 0; j--) {
+ final UriPermission perm = perms.valueAt(j);
+ if (targetPackage != null && !targetPackage.equals(perm.targetPkg)) {
+ continue;
+ }
+ if (perm.uri.sourceUserId == grantUri.sourceUserId
+ && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
+ if (DEBUG) Slog.v(TAG,
+ "Revoking " + perm.targetUid + " permission to " + perm.uri);
+ persistChanged |= perm.revokeModes(
+ modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION,
+ targetPackage == null);
+ if (perm.modeFlags == 0) {
+ perms.removeAt(j);
+ }
+ }
+ }
+
+ if (perms.isEmpty()) {
+ mGrantedUriPermissions.removeAt(i);
+ }
+ }
+
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+
+ /**
+ * Determine if UID is holding permissions required to access {@link Uri} in
+ * the given {@link ProviderInfo}. Final permission checking is always done
+ * in {@link ContentProvider}.
+ */
+ private boolean checkHoldingPermissions(
+ IPackageManager pm, ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
+ if (DEBUG) Slog.v(TAG, "checkHoldingPermissions: uri=" + grantUri + " uid=" + uid);
+ if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
+ if (ActivityManager.checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
+ != PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return checkHoldingPermissionsInternal(pm, pi, grantUri, uid, modeFlags, true);
+ }
+
+ private boolean checkHoldingPermissionsInternal(IPackageManager pm, ProviderInfo pi,
+ GrantUri grantUri, int uid, final int modeFlags, boolean considerUidPermissions) {
+ if (pi.applicationInfo.uid == uid) {
+ return true;
+ } else if (!pi.exported) {
+ return false;
+ }
+
+ boolean readMet = (modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0;
+ boolean writeMet = (modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
+ try {
+ // check if target holds top-level <provider> permissions
+ if (!readMet && pi.readPermission != null && considerUidPermissions
+ && (pm.checkUidPermission(pi.readPermission, uid) == PERMISSION_GRANTED)) {
+ readMet = true;
+ }
+ if (!writeMet && pi.writePermission != null && considerUidPermissions
+ && (pm.checkUidPermission(pi.writePermission, uid) == PERMISSION_GRANTED)) {
+ writeMet = true;
+ }
+
+ // track if unprotected read/write is allowed; any denied
+ // <path-permission> below removes this ability
+ boolean allowDefaultRead = pi.readPermission == null;
+ boolean allowDefaultWrite = pi.writePermission == null;
+
+ // check if target holds any <path-permission> that match uri
+ final PathPermission[] pps = pi.pathPermissions;
+ if (pps != null) {
+ final String path = grantUri.uri.getPath();
+ int i = pps.length;
+ while (i > 0 && (!readMet || !writeMet)) {
+ i--;
+ PathPermission pp = pps[i];
+ if (pp.match(path)) {
+ if (!readMet) {
+ final String pprperm = pp.getReadPermission();
+ if (DEBUG) Slog.v(TAG,
+ "Checking read perm for " + pprperm + " for " + pp.getPath()
+ + ": match=" + pp.match(path)
+ + " check=" + pm.checkUidPermission(pprperm, uid));
+ if (pprperm != null) {
+ if (considerUidPermissions && pm.checkUidPermission(pprperm, uid)
+ == PERMISSION_GRANTED) {
+ readMet = true;
+ } else {
+ allowDefaultRead = false;
+ }
+ }
+ }
+ if (!writeMet) {
+ final String ppwperm = pp.getWritePermission();
+ if (DEBUG) Slog.v(TAG,
+ "Checking write perm " + ppwperm + " for " + pp.getPath()
+ + ": match=" + pp.match(path)
+ + " check=" + pm.checkUidPermission(ppwperm, uid));
+ if (ppwperm != null) {
+ if (considerUidPermissions && pm.checkUidPermission(ppwperm, uid)
+ == PERMISSION_GRANTED) {
+ writeMet = true;
+ } else {
+ allowDefaultWrite = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // grant unprotected <provider> read/write, if not blocked by
+ // <path-permission> above
+ if (allowDefaultRead) readMet = true;
+ if (allowDefaultWrite) writeMet = true;
+
+ } catch (RemoteException e) {
+ return false;
+ }
+
+ return readMet && writeMet;
+ }
+
+ private void removeUriPermissionIfNeeded(UriPermission perm) {
+ if (perm.modeFlags != 0) {
+ return;
+ }
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
+ perm.targetUid);
+ if (perms == null) {
+ return;
+ }
+ if (DEBUG) Slog.v(TAG, "Removing " + perm.targetUid + " permission to " + perm.uri);
+
+ perms.remove(perm.uri);
+ if (perms.isEmpty()) {
+ mGrantedUriPermissions.remove(perm.targetUid);
+ }
+ }
+
+ private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
+ final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+ if (targetUris != null) {
+ return targetUris.get(grantUri);
+ }
+ return null;
+ }
+
+ private void schedulePersistUriGrants() {
+ if (!mH.hasMessages(PERSIST_URI_GRANTS_MSG)) {
+ mH.sendMessageDelayed(mH.obtainMessage(PERSIST_URI_GRANTS_MSG),
+ 10 * DateUtils.SECOND_IN_MILLIS);
+ }
+ }
+
+ private void enforceNotIsolatedCaller(String caller) {
+ if (UserHandle.isIsolated(Binder.getCallingUid())) {
+ throw new SecurityException("Isolated process not allowed to call " + caller);
+ }
+ }
+
+ private ProviderInfo getProviderInfo(String authority, int userHandle, int pmFlags) {
+ ProviderInfo pi = null;
+ try {
+ pi = AppGlobals.getPackageManager().resolveContentProvider(
+ authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags,
+ userHandle);
+ } catch (RemoteException ex) {
+ }
+ return pi;
+ }
+
+ /**
+ * Check if the targetPkg can be granted permission to access uri by
+ * the callingUid using the given modeFlags. Throws a security exception
+ * if callingUid is not allowed to do this. Returns the uid of the target
+ * if the URI permission grant should be performed; returns -1 if it is not
+ * needed (for example targetPkg already has permission to access the URI).
+ * If you already know the uid of the target, you can supply it in
+ * lastTargetUid else set that to -1.
+ */
+ int checkGrantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ final int modeFlags, int lastTargetUid) {
+ if (!Intent.isAccessUriMode(modeFlags)) {
+ return -1;
+ }
+
+ if (targetPkg != null) {
+ if (DEBUG) Slog.v(TAG, "Checking grant " + targetPkg + " permission to " + grantUri);
+ }
+
+ final IPackageManager pm = AppGlobals.getPackageManager();
+
+ // If this is not a content: uri, we can't do anything with it.
+ if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
+ if (DEBUG) Slog.v(TAG, "Can't grant URI permission for non-content URI: " + grantUri);
+ return -1;
+ }
+
+ // Bail early if system is trying to hand out permissions directly; it
+ // must always grant permissions on behalf of someone explicit.
+ final int callingAppId = UserHandle.getAppId(callingUid);
+ if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
+ if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {
+ // Exempted authority for
+ // 1. cropping user photos and sharing a generated license html
+ // file in Settings app
+ // 2. sharing a generated license html file in TvSettings app
+ } else {
+ Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
+ + " grant to " + grantUri + "; use startActivityAsCaller() instead");
+ return -1;
+ }
+ }
+
+ final String authority = grantUri.uri.getAuthority();
+ final ProviderInfo pi = getProviderInfo(authority, grantUri.sourceUserId,
+ MATCH_DEBUG_TRIAGED_MISSING);
+ if (pi == null) {
+ Slog.w(TAG, "No content provider found for permission check: " +
+ grantUri.uri.toSafeString());
+ return -1;
+ }
+
+ int targetUid = lastTargetUid;
+ if (targetUid < 0 && targetPkg != null) {
+ try {
+ targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.getUserId(callingUid));
+ if (targetUid < 0) {
+ if (DEBUG) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg);
+ return -1;
+ }
+ } catch (RemoteException ex) {
+ return -1;
+ }
+ }
+
+ // If we're extending a persistable grant, then we always need to create
+ // the grant data structure so that take/release APIs work
+ if ((modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0) {
+ return targetUid;
+ }
+
+ if (targetUid >= 0) {
+ // First... does the target actually need this permission?
+ if (checkHoldingPermissions(pm, pi, grantUri, targetUid, modeFlags)) {
+ // No need to grant the target this permission.
+ if (DEBUG) Slog.v(TAG,
+ "Target " + targetPkg + " already has full permission to " + grantUri);
+ return -1;
+ }
+ } else {
+ // First... there is no target package, so can anyone access it?
+ boolean allowed = pi.exported;
+ if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (pi.readPermission != null) {
+ allowed = false;
+ }
+ }
+ if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (pi.writePermission != null) {
+ allowed = false;
+ }
+ }
+ if (pi.pathPermissions != null) {
+ final int N = pi.pathPermissions.length;
+ for (int i=0; i<N; i++) {
+ if (pi.pathPermissions[i] != null
+ && pi.pathPermissions[i].match(grantUri.uri.getPath())) {
+ if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (pi.pathPermissions[i].getReadPermission() != null) {
+ allowed = false;
+ }
+ }
+ if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (pi.pathPermissions[i].getWritePermission() != null) {
+ allowed = false;
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (allowed) {
+ return -1;
+ }
+ }
+
+ /* There is a special cross user grant if:
+ * - The target is on another user.
+ * - Apps on the current user can access the uri without any uid permissions.
+ * In this case, we grant a uri permission, even if the ContentProvider does not normally
+ * grant uri permissions.
+ */
+ boolean specialCrossUserGrant = UserHandle.getUserId(targetUid) != grantUri.sourceUserId
+ && checkHoldingPermissionsInternal(pm, pi, grantUri, callingUid,
+ modeFlags, false /*without considering the uid permissions*/);
+
+ // Second... is the provider allowing granting of URI permissions?
+ if (!specialCrossUserGrant) {
+ if (!pi.grantUriPermissions) {
+ throw new SecurityException("Provider " + pi.packageName
+ + "/" + pi.name
+ + " does not allow granting of Uri permissions (uri "
+ + grantUri + ")");
+ }
+ if (pi.uriPermissionPatterns != null) {
+ final int N = pi.uriPermissionPatterns.length;
+ boolean allowed = false;
+ for (int i=0; i<N; i++) {
+ if (pi.uriPermissionPatterns[i] != null
+ && pi.uriPermissionPatterns[i].match(grantUri.uri.getPath())) {
+ allowed = true;
+ break;
+ }
+ }
+ if (!allowed) {
+ throw new SecurityException("Provider " + pi.packageName
+ + "/" + pi.name
+ + " does not allow granting of permission to path of Uri "
+ + grantUri);
+ }
+ }
+ }
+
+ // Third... does the caller itself have permission to access this uri?
+ if (!checkHoldingPermissions(pm, pi, grantUri, callingUid, modeFlags)) {
+ // Require they hold a strong enough Uri permission
+ if (!checkUriPermission(grantUri, callingUid, modeFlags)) {
+ if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(pi.readPermission)) {
+ throw new SecurityException(
+ "UID " + callingUid + " does not have permission to " + grantUri
+ + "; you could obtain access using ACTION_OPEN_DOCUMENT "
+ + "or related APIs");
+ } else {
+ throw new SecurityException(
+ "UID " + callingUid + " does not have permission to " + grantUri);
+ }
+ }
+ }
+ return targetUid;
+ }
+
+ /**
+ * @param userId The userId in which the uri is to be resolved.
+ */
+ int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags,
+ int userId) {
+ return checkGrantUriPermission(callingUid, targetPkg,
+ new GrantUri(userId, uri, false), modeFlags, -1);
+ }
+
+ boolean checkUriPermission(GrantUri grantUri, int uid, final int modeFlags) {
+ final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
+ final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
+ : UriPermission.STRENGTH_OWNED;
+
+ // Root gets to do everything.
+ if (uid == 0) {
+ return true;
+ }
+
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+ if (perms == null) return false;
+
+ // First look for exact match
+ final UriPermission exactPerm = perms.get(grantUri);
+ if (exactPerm != null && exactPerm.getStrength(modeFlags) >= minStrength) {
+ return true;
+ }
+
+ // No exact match, look for prefixes
+ final int N = perms.size();
+ for (int i = 0; i < N; i++) {
+ final UriPermission perm = perms.valueAt(i);
+ if (perm.uri.prefix && grantUri.uri.isPathPrefixMatch(perm.uri.uri)
+ && perm.getStrength(modeFlags) >= minStrength) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void writeGrantedUriPermissions() {
+ if (DEBUG) Slog.v(TAG, "writeGrantedUriPermissions()");
+
+ final long startTime = SystemClock.uptimeMillis();
+
+ // Snapshot permissions so we can persist without lock
+ ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
+ synchronized (this) {
+ final int size = mGrantedUriPermissions.size();
+ for (int i = 0; i < size; i++) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+ for (UriPermission perm : perms.values()) {
+ if (perm.persistedModeFlags != 0) {
+ persist.add(perm.snapshot());
+ }
+ }
+ }
+ }
+
+ FileOutputStream fos = null;
+ try {
+ fos = mGrantFile.startWrite(startTime);
+
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(fos, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, TAG_URI_GRANTS);
+ for (UriPermission.Snapshot perm : persist) {
+ out.startTag(null, TAG_URI_GRANT);
+ writeIntAttribute(out, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId);
+ writeIntAttribute(out, ATTR_TARGET_USER_ID, perm.targetUserId);
+ out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
+ out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
+ out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri));
+ writeBooleanAttribute(out, ATTR_PREFIX, perm.uri.prefix);
+ writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
+ writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
+ out.endTag(null, TAG_URI_GRANT);
+ }
+ out.endTag(null, TAG_URI_GRANTS);
+ out.endDocument();
+
+ mGrantFile.finishWrite(fos);
+ } catch (IOException e) {
+ if (fos != null) {
+ mGrantFile.failWrite(fos);
+ }
+ }
+ }
+
+ final class H extends Handler {
+ static final int PERSIST_URI_GRANTS_MSG = 1;
+
+ public H(Looper looper) {
+ super(looper, null, true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case PERSIST_URI_GRANTS_MSG: {
+ writeGrantedUriPermissions();
+ break;
+ }
+ }
+ }
+ }
+
+ final class LocalService implements UriGrantsManagerInternal {
+
+ @Override
+ public void removeUriPermissionIfNeeded(UriPermission perm) {
+ synchronized (mLock) {
+ UriGrantsManagerService.this.removeUriPermissionIfNeeded(perm);
+ }
+ }
+
+ @Override
+ public void grantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ int modeFlags, UriPermissionOwner owner, int targetUserId) {
+ synchronized (mLock) {
+ UriGrantsManagerService.this.grantUriPermission(
+ callingUid, targetPkg, grantUri, modeFlags, owner, targetUserId);
+ }
+ }
+
+ @Override
+ public void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
+ int modeFlags) {
+ synchronized (mLock) {
+ UriGrantsManagerService.this.revokeUriPermission(
+ targetPackage, callingUid, grantUri, modeFlags);
+ }
+ }
+
+ @Override
+ public boolean checkUriPermission(GrantUri grantUri, int uid, int modeFlags) {
+ synchronized (mLock) {
+ return UriGrantsManagerService.this.checkUriPermission(grantUri, uid, modeFlags);
+ }
+ }
+
+ @Override
+ public int checkGrantUriPermission(int callingUid, String targetPkg, GrantUri uri,
+ int modeFlags, int userId) {
+ synchronized (mLock) {
+ return UriGrantsManagerService.this.checkGrantUriPermission(
+ callingUid, targetPkg, uri, modeFlags, userId);
+ }
+ }
+
+ @Override
+ public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags,
+ int userId) {
+ enforceNotIsolatedCaller("checkGrantUriPermission");
+ synchronized (mLock) {
+ return UriGrantsManagerService.this.checkGrantUriPermission(
+ callingUid, targetPkg, uri, modeFlags, userId);
+ }
+ }
+
+ @Override
+ public NeededUriGrants checkGrantUriPermissionFromIntent(int callingUid, String targetPkg,
+ Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
+ synchronized (mLock) {
+ return UriGrantsManagerService.this.checkGrantUriPermissionFromIntent(
+ callingUid, targetPkg, intent, mode, needed, targetUserId);
+ }
+ }
+
+ @Override
+ public void grantUriPermissionFromIntent(int callingUid, String targetPkg, Intent intent,
+ int targetUserId) {
+ synchronized (mLock) {
+ UriGrantsManagerService.this.grantUriPermissionFromIntent(
+ callingUid, targetPkg, intent, null, targetUserId);
+ }
+ }
+
+ @Override
+ public void grantUriPermissionFromIntent(int callingUid, String targetPkg, Intent intent,
+ UriPermissionOwner owner, int targetUserId) {
+ synchronized (mLock) {
+ UriGrantsManagerService.this.grantUriPermissionFromIntent(
+ callingUid, targetPkg, intent, owner, targetUserId);
+ }
+ }
+
+ @Override
+ public void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed,
+ UriPermissionOwner owner) {
+ synchronized (mLock) {
+ UriGrantsManagerService.this.grantUriPermissionUncheckedFromIntent(needed, owner);
+ }
+ }
+
+ @Override
+ public void onSystemReady() {
+ synchronized (mLock) {
+ UriGrantsManagerService.this.readGrantedUriPermissions();
+ }
+ }
+
+ @Override
+ public void onActivityManagerInternalAdded() {
+ synchronized (mLock) {
+ UriGrantsManagerService.this.onActivityManagerInternalAdded();
+ }
+ }
+
+ @Override
+ public IBinder newUriPermissionOwner(String name) {
+ enforceNotIsolatedCaller("newUriPermissionOwner");
+ synchronized(mLock) {
+ UriPermissionOwner owner = new UriPermissionOwner(this, name);
+ return owner.getExternalToken();
+ }
+ }
+
+ @Override
+ public void removeUriPermissionsForPackage(String packageName, int userHandle,
+ boolean persistable, boolean targetOnly) {
+ synchronized(mLock) {
+ UriGrantsManagerService.this.removeUriPermissionsForPackage(
+ packageName, userHandle, persistable, targetOnly);
+ }
+ }
+
+ @Override
+ public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) {
+ synchronized(mLock) {
+ final UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+ if (owner == null) {
+ throw new IllegalArgumentException("Unknown owner: " + token);
+ }
+
+ if (uri == null) {
+ owner.removeUriPermissions(mode);
+ } else {
+ final boolean prefix = (mode & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0;
+ owner.removeUriPermission(new GrantUri(userId, uri, prefix), mode);
+ }
+ }
+ }
+
+ @Override
+ public boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId,
+ boolean checkUser) {
+ synchronized(mLock) {
+ return UriGrantsManagerService.this.checkAuthorityGrants(
+ callingUid, cpi, userId, checkUser);
+ }
+ }
+
+ @Override
+ public void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) {
+ synchronized(mLock) {
+ boolean needSep = false;
+ boolean printedAnything = false;
+ if (mGrantedUriPermissions.size() > 0) {
+ boolean printed = false;
+ int dumpUid = -2;
+ if (dumpPackage != null) {
+ try {
+ dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage,
+ MATCH_ANY_USER, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ dumpUid = -1;
+ }
+ }
+ for (int i = 0; i < mGrantedUriPermissions.size(); i++) {
+ int uid = mGrantedUriPermissions.keyAt(i);
+ if (dumpUid >= -1 && UserHandle.getAppId(uid) != dumpUid) {
+ continue;
+ }
+ final ArrayMap<GrantUri, UriPermission> perms =
+ mGrantedUriPermissions.valueAt(i);
+ if (!printed) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" Granted Uri Permissions:");
+ printed = true;
+ printedAnything = true;
+ }
+ pw.print(" * UID "); pw.print(uid); pw.println(" holds:");
+ for (UriPermission perm : perms.values()) {
+ pw.print(" "); pw.println(perm);
+ if (dumpAll) {
+ perm.dump(pw, " ");
+ }
+ }
+ }
+ }
+
+ if (!printedAnything) {
+ pw.println(" (nothing)");
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/uri/UriPermission.java
similarity index 98%
rename from services/core/java/com/android/server/am/UriPermission.java
rename to services/core/java/com/android/server/uri/UriPermission.java
index 1e071aa..bd6348a 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/uri/UriPermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -11,10 +11,10 @@
* 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.
+ * limitations under the License
*/
-package com.android.server.am;
+package com.android.server.uri;
import android.app.GrantedUriPermission;
import android.content.Intent;
@@ -24,7 +24,6 @@
import android.util.Log;
import android.util.Slog;
-import com.android.server.am.ActivityManagerService.GrantUri;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/uri/UriPermissionOwner.java
similarity index 75%
rename from services/core/java/com/android/server/am/UriPermissionOwner.java
rename to services/core/java/com/android/server/uri/UriPermissionOwner.java
index 8eda38e..f814dc6 100644
--- a/services/core/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/uri/UriPermissionOwner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -11,27 +11,30 @@
* 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.
+ * limitations under the License
*/
-package com.android.server.am;
+package com.android.server.uri;
-import android.content.Intent;
+import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
+import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+
import android.os.Binder;
import android.os.IBinder;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
+import com.android.server.am.UriPermissionOwnerProto;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
import java.util.Iterator;
-final class UriPermissionOwner {
- final ActivityManagerService service;
- final Object owner;
+public class UriPermissionOwner {
+ private final UriGrantsManagerInternal mService;
+ private final Object mOwner;
- Binder externalToken;
+ private Binder externalToken;
private ArraySet<UriPermission> mReadPerms;
private ArraySet<UriPermission> mWritePerms;
@@ -42,12 +45,12 @@
}
}
- UriPermissionOwner(ActivityManagerService service, Object owner) {
- this.service = service;
- this.owner = owner;
+ public UriPermissionOwner(UriGrantsManagerInternal service, Object owner) {
+ mService = service;
+ mOwner = owner;
}
- Binder getExternalTokenLocked() {
+ public Binder getExternalToken() {
if (externalToken == null) {
externalToken = new ExternalToken();
}
@@ -61,24 +64,22 @@
return null;
}
- void removeUriPermissionsLocked() {
- removeUriPermissionsLocked(Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ public void removeUriPermissions() {
+ removeUriPermissions(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
}
- void removeUriPermissionsLocked(int mode) {
- removeUriPermissionLocked(null, mode);
+ void removeUriPermissions(int mode) {
+ removeUriPermission(null, mode);
}
- void removeUriPermissionLocked(ActivityManagerService.GrantUri grantUri, int mode) {
- if ((mode & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
- && mReadPerms != null) {
+ void removeUriPermission(GrantUri grantUri, int mode) {
+ if ((mode & FLAG_GRANT_READ_URI_PERMISSION) != 0 && mReadPerms != null) {
Iterator<UriPermission> it = mReadPerms.iterator();
while (it.hasNext()) {
UriPermission perm = it.next();
if (grantUri == null || grantUri.equals(perm.uri)) {
perm.removeReadOwner(this);
- service.removeUriPermissionIfNeededLocked(perm);
+ mService.removeUriPermissionIfNeeded(perm);
it.remove();
}
}
@@ -86,14 +87,14 @@
mReadPerms = null;
}
}
- if ((mode & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
+ if ((mode & FLAG_GRANT_WRITE_URI_PERMISSION) != 0
&& mWritePerms != null) {
Iterator<UriPermission> it = mWritePerms.iterator();
while (it.hasNext()) {
UriPermission perm = it.next();
if (grantUri == null || grantUri.equals(perm.uri)) {
perm.removeWriteOwner(this);
- service.removeUriPermissionIfNeededLocked(perm);
+ mService.removeUriPermissionIfNeeded(perm);
it.remove();
}
}
@@ -142,7 +143,7 @@
public void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
- proto.write(UriPermissionOwnerProto.OWNER, owner.toString());
+ proto.write(UriPermissionOwnerProto.OWNER, mOwner.toString());
if (mReadPerms != null) {
synchronized (mReadPerms) {
for (UriPermission p : mReadPerms) {
@@ -162,6 +163,6 @@
@Override
public String toString() {
- return owner.toString();
+ return mOwner.toString();
}
}
diff --git a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
index 51d5eea..20a13334 100644
--- a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
+++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
@@ -18,6 +18,7 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.UriGrantsManager;
import android.content.ClipData;
import android.net.Uri;
import android.os.Binder;
@@ -25,6 +26,8 @@
import android.os.RemoteException;
import com.android.internal.view.IDragAndDropPermissions;
+import com.android.server.LocalServices;
+import com.android.server.uri.UriGrantsManagerInternal;
import java.util.ArrayList;
@@ -72,7 +75,7 @@
long origId = Binder.clearCallingIdentity();
try {
for (int i = 0; i < mUris.size(); i++) {
- ActivityManager.getService().grantUriPermissionFromOwner(
+ UriGrantsManager.getService().grantUriPermissionFromOwner(
permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode,
mSourceUserId, mTargetUserId);
}
@@ -86,7 +89,8 @@
if (mActivityToken != null || mPermissionOwnerToken != null) {
return;
}
- mPermissionOwnerToken = ActivityManager.getService().newUriPermissionOwner("drop");
+ mPermissionOwnerToken = LocalServices.getService(UriGrantsManagerInternal.class)
+ .newUriPermissionOwner("drop");
mTransientToken = transientToken;
mTransientToken.linkToDeath(this, 0);
@@ -117,9 +121,9 @@
mTransientToken = null;
}
+ UriGrantsManagerInternal ugm = LocalServices.getService(UriGrantsManagerInternal.class);
for (int i = 0; i < mUris.size(); ++i) {
- ActivityManager.getService().revokeUriPermissionFromOwner(
- permissionOwner, mUris.get(i), mMode, mSourceUserId);
+ ugm.revokeUriPermissionFromOwner(permissionOwner, mUris.get(i), mMode, mSourceUserId);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ed4d4db..81ac6a4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -233,6 +233,7 @@
import com.android.server.pm.UserRestrictionsUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.uri.UriGrantsManagerInternal;
import com.google.android.collect.Sets;
import org.xmlpull.v1.XmlPullParser;
@@ -6973,7 +6974,7 @@
intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- LocalServices.getService(ActivityManagerInternal.class)
+ LocalServices.getService(UriGrantsManagerInternal.class)
.grantUriPermissionFromIntent(Process.SHELL_UID,
mOwners.getDeviceOwnerComponent().getPackageName(),
intent, mOwners.getDeviceOwnerUserId());
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 85de581..2e5a1f8 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -118,6 +118,7 @@
import com.android.server.tv.TvInputManagerService;
import com.android.server.tv.TvRemoteService;
import com.android.server.twilight.TwilightService;
+import com.android.server.uri.UriGrantsManagerService;
import com.android.server.usage.UsageStatsService;
import com.android.server.vr.VrManagerService;
import com.android.server.webkit.WebViewUpdateService;
@@ -562,6 +563,11 @@
mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
traceEnd();
+ // Uri Grants Manager.
+ traceBeginAndSlog("UriGrantsManagerService");
+ mSystemServiceManager.startService(UriGrantsManagerService.Lifecycle.class);
+ traceEnd();
+
// Activity manager runs the show.
traceBeginAndSlog("StartActivityManager");
// TODO: Might need to move after migration to WM.
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 677fd52..7e8697d 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -36,8 +36,8 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
+import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.DisplayWindowController;
import org.junit.Rule;
@@ -103,6 +103,7 @@
if (!sOneTimeSetupDone) {
sOneTimeSetupDone = true;
MockitoAnnotations.initMocks(this);
+ AttributeCache.init(mContext);
}
mHandlerThread = new HandlerThread("ActivityTestsBaseThread");
mHandlerThread.start();
@@ -127,7 +128,6 @@
}
ActivityManagerService setupActivityManagerService(TestActivityTaskManagerService atm) {
- AttributeCache.init(mContext);
final ActivityManagerService am = spy(new TestActivityManagerService(mContext, atm));
setupActivityManagerService(am, atm);
return am;
@@ -137,6 +137,8 @@
atm.setActivityManagerService(am);
atm.mAmInternal = am.new LocalService();
am.mAtmInternal = atm.new LocalService();
+ am.mUgmInternal = mock(UriGrantsManagerInternal.class);
+ atm.mUgmInternal = mock(UriGrantsManagerInternal.class);
// Makes sure the supervisor is using with the spy object.
atm.mStackSupervisor.setService(atm);
doReturn(mock(IPackageManager.class)).when(am).getPackageManager();
diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
index eec852b..56d3a20 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
@@ -13,14 +13,20 @@
*/
package com.android.server;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import android.content.pm.PackageManagerInternal;
+import android.net.Uri;
import android.os.Build;
import android.support.test.InstrumentationRegistry;
import android.testing.TestableContext;
+import com.android.server.uri.UriGrantsManagerInternal;
+
import org.junit.Before;
import org.junit.Rule;
import org.mockito.Mock;
@@ -28,6 +34,7 @@
public class UiServiceTestCase {
@Mock protected PackageManagerInternal mPmi;
+ @Mock protected UriGrantsManagerInternal mUgmInternal;
protected static final String PKG_N_MR1 = "com.example.n_mr1";
protected static final String PKG_O = "com.example.o";
@@ -64,5 +71,10 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
});
+
+ LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
+ LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
+ when(mUgmInternal.checkGrantUriPermission(
+ anyInt(), anyString(), any(Uri.class), anyInt(), anyInt())).thenReturn(-1);
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e7a8b58..a0d145d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -69,6 +69,7 @@
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
+import android.app.IUriGrantsManager;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
@@ -112,11 +113,13 @@
import com.android.internal.R;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.server.LocalServices;
import com.android.server.UiServiceTestCase;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
import com.android.server.notification.NotificationManagerService.NotificationListeners;
+import com.android.server.uri.UriGrantsManagerInternal;
import org.junit.After;
import org.junit.Before;
@@ -187,6 +190,10 @@
IBinder mPermOwner;
@Mock
IActivityManager mAm;
+ @Mock
+ IUriGrantsManager mUgm;
+ @Mock
+ UriGrantsManagerInternal mUgmInternal;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -233,6 +240,9 @@
Secure.NOTIFICATION_BADGING, 1,
UserHandle.getUserHandleForUid(mUid).getIdentifier());
+ LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
+ LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
+
mService = new TestableNotificationManagerService(mContext);
// Use this testable looper.
@@ -251,7 +261,7 @@
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
- when(mAm.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
+ when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
// write to a test file; the system file isn't readable from tests
mFile = new File(mContext.getCacheDir(), "test.xml");
@@ -283,7 +293,7 @@
mListeners, mAssistants, mConditionProviders,
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
mGroupHelper, mAm, mAppUsageStats,
- mock(DevicePolicyManagerInternal.class));
+ mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal);
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
@@ -2578,13 +2588,14 @@
PKG, PKG, 0, "tag", mUid, 0, nbA.build(), new UserHandle(mUid), null, 0), c);
// First post means we grant access to both
- reset(mAm);
- when(mAm.newUriPermissionOwner(any())).thenReturn(new Binder());
+ reset(mUgm);
+ reset(mUgmInternal);
+ when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder());
mService.updateUriPermissions(recordA, null, mContext.getPackageName(),
UserHandle.USER_SYSTEM);
- verify(mAm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
+ verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
- verify(mAm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
+ verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
eq(message2.getDataUri()), anyInt(), anyInt(), anyInt());
Notification.Builder nbB = new Notification.Builder(mContext, c.getId())
@@ -2595,24 +2606,24 @@
PKG, 0, "tag", mUid, 0, nbB.build(), new UserHandle(mUid), null, 0), c);
// Update means we drop access to first
- reset(mAm);
+ reset(mUgmInternal);
mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(),
UserHandle.USER_SYSTEM);
- verify(mAm, times(1)).revokeUriPermissionFromOwner(any(), eq(message1.getDataUri()),
- anyInt(), anyInt());
+ verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(),
+ eq(message1.getDataUri()), anyInt(), anyInt());
// Update back means we grant access to first again
- reset(mAm);
+ reset(mUgm);
mService.updateUriPermissions(recordA, recordB, mContext.getPackageName(),
UserHandle.USER_SYSTEM);
- verify(mAm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
+ verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
// And update to empty means we drop everything
- reset(mAm);
+ reset(mUgmInternal);
mService.updateUriPermissions(null, recordB, mContext.getPackageName(),
UserHandle.USER_SYSTEM);
- verify(mAm, times(1)).revokeUriPermissionFromOwner(any(), eq(null),
+ verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), eq(null),
anyInt(), anyInt());
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index bd6416d..6be633e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -62,6 +62,7 @@
import com.android.internal.R;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.UiServiceTestCase;
+import com.android.server.uri.UriGrantsManagerInternal;
import org.junit.Before;
import org.junit.Test;
@@ -646,7 +647,8 @@
@Test
public void testCalculateGrantableUris_PappProvided() throws RemoteException {
IActivityManager am = mock(IActivityManager.class);
- when(am.checkGrantUriPermission(anyInt(), eq(null), any(),
+ UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
+ when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
Notification n = mock(Notification.class);
@@ -655,6 +657,7 @@
new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.mAm = am;
+ record.mUgmInternal = ugm;
try {
record.calculateGrantableUris();
@@ -667,8 +670,9 @@
@Test
public void testCalculateGrantableUris_PuserOverridden() throws RemoteException {
IActivityManager am = mock(IActivityManager.class);
- when(am.checkGrantUriPermission(anyInt(), eq(null), any(),
- anyInt(), anyInt())).thenThrow(SecurityException.class);
+ UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
+ when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
+ anyInt(), anyInt())).thenThrow(new SecurityException());
channel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
Notification n = mock(Notification.class);
@@ -684,8 +688,9 @@
@Test
public void testCalculateGrantableUris_prePappProvided() throws RemoteException {
IActivityManager am = mock(IActivityManager.class);
- when(am.checkGrantUriPermission(anyInt(), eq(null), any(),
- anyInt(), anyInt())).thenThrow(SecurityException.class);
+ UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
+ when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
+ anyInt(), anyInt())).thenThrow(new SecurityException());
Notification n = mock(Notification.class);
when(n.getChannelId()).thenReturn(channel.getId());
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 01f5d9c..57729b5 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -30,6 +30,7 @@
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.IActivityManager;
+import android.app.UriGrantsManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.content.ClipData;
@@ -62,6 +63,7 @@
import com.android.server.am.AssistDataRequester;
import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.uri.UriGrantsManagerInternal;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -82,6 +84,7 @@
final int mCallingUid;
final Handler mHandler;
final IActivityManager mAm;
+ final UriGrantsManagerInternal mUgmInternal;
final IWindowManager mIWindowManager;
final AppOpsManager mAppOps;
final IBinder mPermissionOwner;
@@ -141,19 +144,15 @@
mCallingUid = callingUid;
mHandler = handler;
mAm = ActivityManager.getService();
+ mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
mAppOps = context.getSystemService(AppOpsManager.class);
mAssistDataRequester = new AssistDataRequester(mContext, mIWindowManager,
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE),
this, mLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
- IBinder permOwner = null;
- try {
- permOwner = mAm.newUriPermissionOwner("voicesession:"
+ final IBinder permOwner = mUgmInternal.newUriPermissionOwner("voicesession:"
+ component.flattenToShortString());
- } catch (RemoteException e) {
- Slog.w("voicesession", "AM dead", e);
- }
mPermissionOwner = permOwner;
mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
mBindIntent.setComponent(mSessionComponentName);
@@ -303,13 +302,14 @@
long ident = Binder.clearCallingIdentity();
try {
// This will throw SecurityException for us.
- mAm.checkGrantUriPermission(srcUid, null, ContentProvider.getUriWithoutUserId(uri),
- mode, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(srcUid)));
+ mUgmInternal.checkGrantUriPermission(srcUid, null,
+ ContentProvider.getUriWithoutUserId(uri), mode,
+ ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(srcUid)));
// No security exception, do the grant.
int sourceUserId = ContentProvider.getUserIdFromUri(uri, mUser);
uri = ContentProvider.getUriWithoutUserId(uri);
- mAm.grantUriPermissionFromOwner(mPermissionOwner, srcUid, destPkg,
- uri, FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, mUser);
+ UriGrantsManager.getService().grantUriPermissionFromOwner(mPermissionOwner, srcUid,
+ destPkg, uri, FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, mUser);
} catch (RemoteException e) {
} catch (SecurityException e) {
Slog.w(TAG, "Can't propagate permission", e);
@@ -352,12 +352,8 @@
} catch (RemoteException e) {
}
}
- try {
- mAm.revokeUriPermissionFromOwner(mPermissionOwner, null,
- FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION,
- mUser);
- } catch (RemoteException e) {
- }
+ mUgmInternal.revokeUriPermissionFromOwner(mPermissionOwner, null,
+ FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION, mUser);
if (mSession != null) {
try {
ActivityTaskManager.getService().finishVoiceTask(mSession);