summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
authorSteve Kondik <shade@chemlab.org>2013-06-12 00:47:55 -0700
committerSteve Kondik <shade@chemlab.org>2013-06-24 11:36:22 -0700
commite48fce6da7bd839d70cbf69abb2780c6d30ea7f6 (patch)
tree49dd160f5a5d10847fd446e0db7f31f2d800792f /services/java
parentb429a08331e8ebea15113fe287f4e5c9478d7001 (diff)
downloadframeworks_base-e48fce6da7bd839d70cbf69abb2780c6d30ea7f6.zip
frameworks_base-e48fce6da7bd839d70cbf69abb2780c6d30ea7f6.tar.gz
frameworks_base-e48fce6da7bd839d70cbf69abb2780c6d30ea7f6.tar.bz2
framework: Privacy Guard
* Introduce a new privacy feature which allows the user to run an application with reduced visibility into his or her personal data. * Adds a per-application flag and simple API to determine if this flag is enabled for the current or calling process. * This flag can be used by content providers to decide if they should return a limited/empty dataset. Change-Id: Id7c54d728e63acb2b02a2a9322930b54949f6c5d
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/LocationManagerService.java58
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java91
-rw-r--r--services/java/com/android/server/am/ActivityStack.java34
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java15
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java59
-rw-r--r--services/java/com/android/server/pm/PackageSettingBase.java11
-rw-r--r--services/java/com/android/server/pm/Settings.java25
7 files changed, 288 insertions, 5 deletions
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 0f08c56..4658156 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.app.ActivityManagerNative;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -664,8 +665,20 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
mProvidersByName.remove(provider.getName());
}
+ private boolean isPrivacyGuardEnabled(int pid) {
+ try {
+ if (ActivityManagerNative.getDefault().isPrivacyGuardEnabledForProcess(pid)) {
+ Slog.i(TAG, "Location services unavailable under privacy guard for process pid=" + pid);
+ return true;
+ }
+ } catch (RemoteException e) {
+ // nothing
+ }
+ return false;
+ }
private boolean isAllowedBySettingsLocked(String provider, int userId) {
+
if (userId != mCurrentUserId) {
return false;
}
@@ -826,6 +839,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
*/
@Override
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return new ArrayList<String>(0);
+ }
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
ArrayList<String> out;
int callingUserId = UserHandle.getCallingUserId();
@@ -1224,7 +1240,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
- if (isProviderEnabled) {
+ if (isProviderEnabled && !isPrivacyGuardEnabled(pid)) {
applyRequirementsLocked(name);
} else {
// Notify the listener that updates are currently disabled
@@ -1238,6 +1254,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
checkPackageName(packageName);
final int pid = Binder.getCallingPid();
+ if (isPrivacyGuardEnabled(pid)) {
+ return;
+ }
final int uid = Binder.getCallingUid();
Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
@@ -1297,6 +1316,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
// no need to sanitize this request, as only the provider name is used
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return null;
+ }
long identity = Binder.clearCallingIdentity();
try {
@@ -1349,8 +1371,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return;
+ }
+
// geo-fence manager uses the public location API, need to clear identity
int uid = Binder.getCallingUid();
+
if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
// temporary measure until geofences work for secondary users
Log.w(TAG, "proximity alerts are currently available only to the primary user");
@@ -1372,6 +1399,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return;
+ }
+
// geo-fence manager uses the public location API, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
@@ -1390,6 +1421,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
LocationManager.GPS_PROVIDER);
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return false;
+ }
+
try {
mGpsStatusProvider.addGpsStatusListener(listener);
} catch (RemoteException e) {
@@ -1401,6 +1436,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
@Override
public void removeGpsStatusListener(IGpsStatusListener listener) {
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return;
+ }
+
synchronized (mLock) {
try {
mGpsStatusProvider.removeGpsStatusListener(listener);
@@ -1419,6 +1458,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return false;
+ }
+
// and check for ACCESS_LOCATION_EXTRA_COMMANDS
if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
!= PackageManager.PERMISSION_GRANTED)) {
@@ -1439,6 +1482,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
throw new SecurityException(
"calling sendNiResponse from outside of the system is not allowed");
}
+
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return false;
+ }
+
try {
return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
} catch (RemoteException e) {
@@ -1461,6 +1509,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return null;
+ }
+
LocationProviderInterface p;
synchronized (mLock) {
p = mProvidersByName.get(provider);
@@ -1476,6 +1528,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
provider);
if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
+ if (isPrivacyGuardEnabled(Binder.getCallingPid())) {
+ return false;
+ }
+
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c068982..618f02c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -120,6 +120,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.provider.Telephony.Sms.Intents;
import android.text.format.Time;
import android.util.EventLog;
import android.util.Log;
@@ -901,6 +902,9 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int CONTINUE_USER_SWITCH_MSG = 35;
static final int USER_SWITCH_TIMEOUT_MSG = 36;
+ static final int POST_PRIVACY_NOTIFICATION_MSG = 40;
+ static final int CANCEL_PRIVACY_NOTIFICATION_MSG = 41;
+
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
static final int FIRST_COMPAT_MODE_MSG = 300;
@@ -1361,6 +1365,69 @@ public final class ActivityManagerService extends ActivityManagerNative
timeoutUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
break;
}
+ case POST_PRIVACY_NOTIFICATION_MSG: {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+
+ ActivityRecord root = (ActivityRecord)msg.obj;
+ ProcessRecord process = root.app;
+ if (process == null) {
+ return;
+ }
+
+ try {
+ Context context = mContext.createPackageContext(process.info.packageName, 0);
+ String text = mContext.getString(R.string.privacy_guard_notification_detail,
+ context.getApplicationInfo().loadLabel(context.getPackageManager()));
+ String title = mContext.getString(R.string.privacy_guard_notification);
+
+ Intent infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", root.packageName, null));
+
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_notify_privacy_guard;
+ notification.when = 0;
+ notification.flags = Notification.FLAG_ONGOING_EVENT;
+ notification.priority = Notification.PRIORITY_LOW;
+ notification.defaults = 0;
+ notification.sound = null;
+ notification.vibrate = null;
+ notification.setLatestEventInfo(getUiContext(),
+ title, text,
+ PendingIntent.getActivityAsUser(mContext, 0, infoIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null,
+ new UserHandle(root.userId)));
+
+ try {
+ int[] outId = new int[1];
+ inm.enqueueNotificationWithTag("android", null,
+ R.string.privacy_guard_notification,
+ notification, outId, root.userId);
+ } catch (RuntimeException e) {
+ Slog.w(ActivityManagerService.TAG,
+ "Error showing notification for privacy guard", e);
+ } catch (RemoteException e) {
+ }
+ } catch (NameNotFoundException e) {
+ Slog.w(TAG, "Unable to create context for privacy guard notification", e);
+ }
+ } break;
+ case CANCEL_PRIVACY_NOTIFICATION_MSG: {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+ try {
+ inm.cancelNotificationWithTag("android", null,
+ R.string.privacy_guard_notification, msg.arg1);
+ } catch (RuntimeException e) {
+ Slog.w(ActivityManagerService.TAG,
+ "Error canceling notification for service", e);
+ } catch (RemoteException e) {
+ }
+ } break;
}
}
};
@@ -7426,6 +7493,30 @@ public final class ActivityManagerService extends ActivityManagerNative
return KEY_DISPATCHING_TIMEOUT;
}
+ public boolean isPrivacyGuardEnabledForProcess(int pid) {
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
+ }
+ if (proc == null) {
+ return false;
+ }
+ try {
+ return AppGlobals.getPackageManager().getPrivacyGuardSetting(
+ proc.info.packageName, proc.userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage(), e);
+ }
+ return false;
+ }
+
+ public boolean isFilteredByPrivacyGuard(String intent) {
+ return Intents.SMS_RECEIVED_ACTION.equals(intent) ||
+ Intents.DATA_SMS_RECEIVED_ACTION.equals(intent) ||
+ Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION.equals(intent) ||
+ Intents.SMS_CB_RECEIVED_ACTION.equals(intent);
+ }
+
public void registerProcessObserver(IProcessObserver observer) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerProcessObserver()");
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 885ec89..4e9973f 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1803,9 +1803,43 @@ final class ActivityStack {
startSpecificActivityLocked(next, true, true);
}
+ handlePrivacyGuardNotification(prev, next);
+
return true;
}
+ private final void handlePrivacyGuardNotification(ActivityRecord prev, ActivityRecord next) {
+ boolean curPrivacy = false;
+ boolean prevPrivacy = false;
+
+ if (next != null) {
+ try {
+ curPrivacy = AppGlobals.getPackageManager().getPrivacyGuardSetting(
+ next.packageName, next.userId);
+ } catch (RemoteException e) {
+ // nothing
+ }
+ }
+ if (prev != null) {
+ try {
+ prevPrivacy = AppGlobals.getPackageManager().getPrivacyGuardSetting(
+ prev.packageName, prev.userId);
+ } catch (RemoteException e) {
+ // nothing
+ }
+ }
+ if (prevPrivacy && !curPrivacy) {
+ Message msg = mService.mHandler.obtainMessage(
+ ActivityManagerService.CANCEL_PRIVACY_NOTIFICATION_MSG, prev.userId);
+ msg.sendToTarget();
+ } else if ((!prevPrivacy && curPrivacy) ||
+ (prevPrivacy && curPrivacy && !next.packageName.equals(prev.packageName))) {
+ Message msg = mService.mHandler.obtainMessage(
+ ActivityManagerService.POST_PRIVACY_NOTIFICATION_MSG, next);
+ msg.sendToTarget();
+ }
+ }
+
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
final int NH = mHistory.size();
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index bada7f0..fc4ecda 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -21,6 +21,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.IIntentReceiver;
@@ -409,7 +410,19 @@ public class BroadcastQueue {
skip = true;
}
}
-
+ try {
+ if (!skip && mService.isFilteredByPrivacyGuard(r.intent.getAction()) &&
+ ActivityManagerNative.getDefault().isPrivacyGuardEnabledForProcess(filter.receiverList.pid)) {
+ Slog.w(TAG, "Skipping broadcast of "
+ + r.intent.toString()
+ + " to " + filter.receiverList.app
+ + " (pid=" + filter.receiverList.pid
+ + ") due to privacy guard");
+ skip = true;
+ }
+ } catch (RemoteException e) {
+ // nothing
+ }
if (!skip) {
// If this is not being sent as an ordered broadcast, then we
// don't want to touch the fields that keep track of the current
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 461c060..7702deb 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -8485,11 +8485,16 @@ public class PackageManagerService extends IPackageManager.Stub {
// The caller is asking that the package only be deleted for a single
// user. To do this, we just mark its uninstalled state and delete
// its data.
+ boolean privacyGuard = android.provider.Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ android.provider.Settings.Secure.PRIVACY_GUARD_DEFAULT,
+ 0, user.getIdentifier()) == 1;
ps.setUserState(user.getIdentifier(),
COMPONENT_ENABLED_STATE_DEFAULT,
false, //installed
true, //stopped
true, //notLaunched
+ privacyGuard,
null, null);
if (ps.isAnyInstalled(sUserManager.getUserIds())) {
// Other user still have this package installed, so all
@@ -9033,6 +9038,60 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ public void setPrivacyGuardSetting(String appPackageName,
+ boolean enabled, int userId) {
+ if (!sUserManager.exists(userId)) return;
+ setPrivacyGuard(appPackageName, enabled, userId);
+ }
+
+ @Override
+ public boolean getPrivacyGuardSetting(String packageName, int userId) {
+ if (!sUserManager.exists(userId)) return false;
+ int uid = Binder.getCallingUid();
+ enforceCrossUserPermission(uid, userId, false, "get privacy guard");
+ // reader
+ synchronized (mPackages) {
+ return mSettings.getPrivacyGuardSettingLPr(packageName, userId);
+ }
+ }
+
+ private void setPrivacyGuard(final String packageName,
+ final boolean enabled, final int userId) {
+ PackageSetting pkgSetting;
+ final int uid = Binder.getCallingUid();
+ final int permission = mContext.checkCallingPermission(
+ android.Manifest.permission.CHANGE_PRIVACY_GUARD_STATE);
+ final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+ enforceCrossUserPermission(uid, userId, false, "set privacy guard");
+
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null) {
+ throw new IllegalArgumentException(
+ "Unknown package: " + packageName);
+ }
+ // Allow root and verify that userId is not being specified by a different user
+ if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) {
+ throw new SecurityException(
+ "Permission Denial: attempt to change privacy guard state from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
+ }
+ if (pkgSetting.isPrivacyGuard(userId) == enabled) {
+ // Nothing to do
+ return;
+ }
+ pkgSetting.setPrivacyGuard(enabled, userId);
+ mSettings.writePackageRestrictionsLPr(userId);
+ try {
+ ActivityManagerNative.getDefault().forceStopPackage(packageName, userId);
+ } catch (RemoteException e) {
+ //nothing
+ }
+ }
+ }
+
+ @Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId) {
if (!sUserManager.exists(userId)) return;
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index ae1b213..af45219 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -197,6 +197,14 @@ class PackageSettingBase extends GrantedPermissions {
return readUserState(userId).enabled;
}
+ void setPrivacyGuard(boolean enabled, int userId) {
+ modifyUserState(userId).privacyGuard = enabled;
+ }
+
+ boolean isPrivacyGuard(int userId) {
+ return readUserState(userId).privacyGuard;
+ }
+
void setInstalled(boolean inst, int userId) {
modifyUserState(userId).installed = inst;
}
@@ -249,13 +257,14 @@ class PackageSettingBase extends GrantedPermissions {
}
void setUserState(int userId, int enabled, boolean installed, boolean stopped,
- boolean notLaunched, HashSet<String> enabledComponents,
+ boolean notLaunched, boolean privacyGuard, HashSet<String> enabledComponents,
HashSet<String> disabledComponents) {
PackageUserState state = modifyUserState(userId);
state.enabled = enabled;
state.installed = installed;
state.stopped = stopped;
state.notLaunched = notLaunched;
+ state.privacyGuard = privacyGuard;
state.enabledComponents = enabledComponents;
state.disabledComponents = disabledComponents;
}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 1f568fb..f2074b0 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -100,6 +100,7 @@ final class Settings {
private static final String ATTR_ENABLED = "enabled";
private static final String ATTR_STOPPED = "stopped";
private static final String ATTR_INSTALLED = "inst";
+ private static final String ATTR_PRIVACY_GUARD = "privacy-guard";
private final File mSettingsFilename;
private final File mBackupSettingsFilename;
@@ -443,10 +444,15 @@ final class Settings {
final boolean installed = installUser == null
|| installUser.getIdentifier() == UserHandle.USER_ALL
|| installUser.getIdentifier() == user.id;
+ final boolean privacyGuard = android.provider.Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ android.provider.Settings.Secure.PRIVACY_GUARD_DEFAULT,
+ 0, user.id) == 1;
p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT,
installed,
true, // stopped,
true, // notLaunched
+ privacyGuard,
null, null);
writePackageRestrictionsLPr(user.id);
}
@@ -844,6 +850,7 @@ final class Settings {
true, // installed
false, // stopped
false, // notLaunched
+ false, // privacy guard
null, null);
}
return;
@@ -898,6 +905,9 @@ final class Settings {
final String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
final boolean notLaunched = stoppedStr == null
? false : Boolean.parseBoolean(notLaunchedStr);
+ final String privacyGuardStr = parser.getAttributeValue(null, ATTR_PRIVACY_GUARD);
+ final boolean privacyGuard = privacyGuardStr == null
+ ? false : Boolean.parseBoolean(privacyGuardStr);
HashSet<String> enabledComponents = null;
HashSet<String> disabledComponents = null;
@@ -918,7 +928,7 @@ final class Settings {
}
}
- ps.setUserState(userId, enabled, installed, stopped, notLaunched,
+ ps.setUserState(userId, enabled, installed, stopped, notLaunched, privacyGuard,
enabledComponents, disabledComponents);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
@@ -1024,7 +1034,7 @@ final class Settings {
for (final PackageSetting pkg : mPackages.values()) {
PackageUserState ustate = pkg.readUserState(userId);
- if (ustate.stopped || ustate.notLaunched || !ustate.installed
+ if (ustate.stopped || ustate.notLaunched || !ustate.installed || ustate.privacyGuard
|| ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
|| (ustate.enabledComponents != null
&& ustate.enabledComponents.size() > 0)
@@ -1047,6 +1057,9 @@ final class Settings {
serializer.attribute(null, ATTR_ENABLED,
Integer.toString(ustate.enabled));
}
+ if (ustate.privacyGuard) {
+ serializer.attribute(null, ATTR_PRIVACY_GUARD, "true");
+ }
if (ustate.enabledComponents != null
&& ustate.enabledComponents.size() > 0) {
serializer.startTag(null, TAG_ENABLED_COMPONENTS);
@@ -2437,6 +2450,14 @@ final class Settings {
return pkg.installerPackageName;
}
+ boolean getPrivacyGuardSettingLPr(String packageName, int userId) {
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.isPrivacyGuard(userId);
+ }
+
int getApplicationEnabledSettingLPr(String packageName, int userId) {
final PackageSetting pkg = mPackages.get(packageName);
if (pkg == null) {