summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorSander Alewijnse <salewijnse@google.com>2014-02-17 15:13:58 +0000
committerSander Alewijnse <salewijnse@google.com>2014-02-21 15:24:20 +0000
commitf475ca33d9232785710aaa438f17915029dfa83b (patch)
treeca3ac28738e66281dc97546a9132a45cca69bc8f /services
parentc4f6c351e18380e712d5d365d2a13cfa5674daf7 (diff)
downloadframeworks_base-f475ca33d9232785710aaa438f17915029dfa83b.zip
frameworks_base-f475ca33d9232785710aaa438f17915029dfa83b.tar.gz
frameworks_base-f475ca33d9232785710aaa438f17915029dfa83b.tar.bz2
Enables a profile owner or device owner to set and clear default intent handler activities.
Those intent handlers are persistent preferences. They will remain the default intent handler even if the set of potential event handlers for the intent filter changes and if the intent preferences are reset. Change-Id: Id0cfae46f93c10d89e441f272096a205ec518dd0
Diffstat (limited to 'services')
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageManagerService.java132
-rw-r--r--services/core/java/com/android/server/pm/PersistentPreferredActivity.java96
-rw-r--r--services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java34
-rw-r--r--services/core/java/com/android/server/pm/Settings.java57
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java62
5 files changed, 381 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 84f0f2e..07a74cd 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2777,6 +2777,63 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
+ private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
+ int flags, List<ResolveInfo> query, boolean debug, int userId) {
+ final int N = query.size();
+ PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
+ .get(userId);
+ // Get the list of persistent preferred activities that handle the intent
+ if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities...");
+ List<PersistentPreferredActivity> pprefs = ppir != null
+ ? ppir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId)
+ : null;
+ if (pprefs != null && pprefs.size() > 0) {
+ final int M = pprefs.size();
+ for (int i=0; i<M; i++) {
+ final PersistentPreferredActivity ppa = pprefs.get(i);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Checking PersistentPreferredActivity ds="
+ + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
+ + "\n component=" + ppa.mComponent);
+ ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ }
+ final ActivityInfo ai = getActivityInfo(ppa.mComponent,
+ flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Found persistent preferred activity:");
+ if (ai != null) {
+ ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ } else {
+ Slog.v(TAG, " null");
+ }
+ }
+ if (ai == null) {
+ // This previously registered persistent preferred activity
+ // component is no longer known. Ignore it and do NOT remove it.
+ continue;
+ }
+ for (int j=0; j<N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (!ri.activityInfo.applicationInfo.packageName
+ .equals(ai.applicationInfo.packageName)) {
+ continue;
+ }
+ if (!ri.activityInfo.name.equals(ai.name)) {
+ continue;
+ }
+ // Found a persistent preference that can handle the intent.
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Returning persistent preferred activity: " +
+ ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+ }
+ return ri;
+ }
+ }
+ }
+ return null;
+ }
+
ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId) {
@@ -2787,6 +2844,16 @@ public class PackageManagerService extends IPackageManager.Stub {
intent = intent.getSelector();
}
if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
+
+ // Try to find a matching persistent preferred activity.
+ ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query,
+ debug, userId);
+
+ // If a persistent preferred activity matched, use it.
+ if (pri != null) {
+ return pri;
+ }
+
PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
// Get the list of preferred activities that handle the intent
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
@@ -10341,6 +10408,71 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
+ int userId) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException(
+ "addPersistentPreferredActivity can only be run by the system");
+ }
+ if (filter.countActions() == 0) {
+ Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
+ return;
+ }
+ synchronized (mPackages) {
+ Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId +
+ " :");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
+ new PersistentPreferredActivity(filter, activity));
+ mSettings.writePackageRestrictionsLPr(userId);
+ }
+ }
+
+ @Override
+ public void clearPackagePersistentPreferredActivities(String packageName, int userId) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException(
+ "clearPackagePersistentPreferredActivities can only be run by the system");
+ }
+ ArrayList<PersistentPreferredActivity> removed = null;
+ boolean changed = false;
+ synchronized (mPackages) {
+ for (int i=0; i<mSettings.mPersistentPreferredActivities.size(); i++) {
+ final int thisUserId = mSettings.mPersistentPreferredActivities.keyAt(i);
+ PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
+ .valueAt(i);
+ if (userId != thisUserId) {
+ continue;
+ }
+ Iterator<PersistentPreferredActivity> it = ppir.filterIterator();
+ while (it.hasNext()) {
+ PersistentPreferredActivity ppa = it.next();
+ // Mark entry for removal only if it matches the package name.
+ if (ppa.mComponent.getPackageName().equals(packageName)) {
+ if (removed == null) {
+ removed = new ArrayList<PersistentPreferredActivity>();
+ }
+ removed.add(ppa);
+ }
+ }
+ if (removed != null) {
+ for (int j=0; j<removed.size(); j++) {
+ PersistentPreferredActivity ppa = removed.get(j);
+ ppir.removeFilter(ppa);
+ }
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ mSettings.writePackageRestrictionsLPr(userId);
+ }
+ }
+ }
+
+ @Override
public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
new file mode 100644
index 0000000..4284a6d
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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.pm;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import java.io.IOException;
+
+class PersistentPreferredActivity extends IntentFilter {
+ private static final String ATTR_NAME = "name"; // component name
+ private static final String ATTR_FILTER = "filter"; // filter
+
+ private static final String TAG = "PersistentPreferredActivity";
+
+ private static final boolean DEBUG_FILTERS = false;
+
+ final ComponentName mComponent;
+
+ PersistentPreferredActivity(IntentFilter filter, ComponentName activity) {
+ super(filter);
+ mComponent = activity;
+ }
+
+ PersistentPreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String shortComponent = parser.getAttributeValue(null, ATTR_NAME);
+ mComponent = ComponentName.unflattenFromString(shortComponent);
+ if (mComponent == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings <hard-preferred-activity>: " +
+ "Bad activity name " + shortComponent +
+ " at " + parser.getPositionDescription());
+ }
+ int outerDepth = parser.getDepth();
+ String tagName = parser.getName();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ tagName = parser.getName();
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ } else if (type == XmlPullParser.START_TAG) {
+ if (tagName.equals(ATTR_FILTER)) {
+ break;
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <hard-preferred-activity>: " + tagName +
+ " at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+ if (tagName.equals(ATTR_FILTER)) {
+ readFromXml(parser);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Missing element under <hard-preferred-activity>: filter at " +
+ parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ public void writeToXml(XmlSerializer serializer) throws IOException {
+ serializer.attribute(null, ATTR_NAME, mComponent.flattenToShortString());
+ serializer.startTag(null, ATTR_FILTER);
+ super.writeToXml(serializer);
+ serializer.endTag(null, ATTR_FILTER);
+ }
+
+ @Override
+ public String toString() {
+ return "PersistentPreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))
+ + " " + mComponent.flattenToShortString() + "}";
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
new file mode 100644
index 0000000..9c8a9bd
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 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.pm;
+
+import java.io.PrintWriter;
+
+import com.android.server.IntentResolver;
+
+public class PersistentPreferredIntentResolver
+ extends IntentResolver<PersistentPreferredActivity, PersistentPreferredActivity> {
+ @Override
+ protected PersistentPreferredActivity[] newArray(int size) {
+ return new PersistentPreferredActivity[size];
+ }
+
+ @Override
+ protected boolean isPackageForFilter(String packageName, PersistentPreferredActivity filter) {
+ return packageName.equals(filter.mComponent.getPackageName());
+ }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e7c6446..9236bde 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -141,6 +141,11 @@ final class Settings {
final SparseArray<PreferredIntentResolver> mPreferredActivities =
new SparseArray<PreferredIntentResolver>();
+ // The persistent preferred activities of the user's profile/device owner
+ // associated with particular intent filters.
+ final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
+ new SparseArray<PersistentPreferredIntentResolver>();
+
final HashMap<String, SharedUserSetting> mSharedUsers =
new HashMap<String, SharedUserSetting>();
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
@@ -776,6 +781,15 @@ final class Settings {
return pir;
}
+ PersistentPreferredIntentResolver editPersistentPreferredActivitiesLPw(int userId) {
+ PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
+ if (ppir == null) {
+ ppir = new PersistentPreferredIntentResolver();
+ mPersistentPreferredActivities.put(userId, ppir);
+ }
+ return ppir;
+ }
+
private File getUserPackagesStateFile(int userId) {
return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
}
@@ -835,6 +849,27 @@ final class Settings {
}
}
+ private void readPersistentPreferredActivitiesLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ PersistentPreferredActivity ppa = new PersistentPreferredActivity(parser);
+ editPersistentPreferredActivitiesLPw(userId).addFilter(ppa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <hard-preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
void readPackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -961,6 +996,8 @@ final class Settings {
enabledCaller, enabledComponents, disabledComponents);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
+ } else if (tagName.equals("hard-preferred-activities")) {
+ readPersistentPreferredActivitiesLPw(parser, userId);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ parser.getName());
@@ -1024,6 +1061,20 @@ final class Settings {
serializer.endTag(null, "preferred-activities");
}
+ void writePersistentPreferredActivitiesLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, "hard-preferred-activities");
+ PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
+ if (ppir != null) {
+ for (final PersistentPreferredActivity ppa : ppir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ ppa.writeToXml(serializer);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, "hard-preferred-activities");
+ }
+
void writePackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1120,6 +1171,8 @@ final class Settings {
writePreferredActivitiesLPr(serializer, userId, true);
+ writePersistentPreferredActivitiesLPr(serializer, userId);
+
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
serializer.endDocument();
@@ -1721,6 +1774,10 @@ final class Settings {
// Upgrading from old single-user implementation;
// these are the preferred activities for user 0.
readPreferredActivitiesLPw(parser, 0);
+ } else if (tagName.equals("hard-preferred-activities")) {
+ // TODO: check whether this is okay! as it is very
+ // similar to how preferred-activities are treated
+ readPersistentPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 12f0114..92ed75b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2966,4 +2966,66 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
}
+
+ private boolean isProfileOwner(String packageName, int userId) {
+ String profileOwnerPackage = getProfileOwner(userId);
+ // TODO: make public and connect with isProfileOwnerApp in DPM
+ return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
+ }
+
+ public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter,
+ ComponentName activity) {
+ int callingUserId = UserHandle.getCallingUserId();
+ Slog.d(LOG_TAG,"called by user " + callingUserId);
+ synchronized (this) {
+ ActiveAdmin aa = getActiveAdminUncheckedLocked(admin, callingUserId);
+ if (aa == null) {
+ throw new SecurityException("No active admin " + admin);
+ } else {
+ if (isProfileOwner(admin.getPackageName(), callingUserId)
+ || isDeviceOwner(admin.getPackageName())) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ long id = Binder.clearCallingIdentity();
+ try {
+ pm.addPersistentPreferredActivity(filter, activity, callingUserId);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ } else {
+ throw new SecurityException("Admin " + admin +
+ "is not device owner or profile owner" );
+ }
+ }
+ }
+ }
+
+ public void clearPackagePersistentPreferredActivities(ComponentName admin,
+ String packageName) {
+ int callingUserId = UserHandle.getCallingUserId();
+ Slog.d(LOG_TAG,"called by user " + callingUserId);
+ synchronized (this) {
+ ActiveAdmin aa = getActiveAdminUncheckedLocked(admin, callingUserId);
+ if (aa == null) {
+ throw new SecurityException("No active admin " + admin);
+ } else {
+ if (isProfileOwner(admin.getPackageName(), callingUserId)
+ || isDeviceOwner(admin.getPackageName())) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ long id = Binder.clearCallingIdentity();
+ try{
+ pm.clearPackagePersistentPreferredActivities(packageName, callingUserId);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ } else {
+ throw new SecurityException("Admin " + admin +
+ "is not device owner or profile owner" );
+ }
+ }
+ }
+ }
}