Merge "Improve the logic for determining whether the caller is a system app"
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index eaff7b2..eba69b6 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -101,7 +101,9 @@
     String getNameForUid(int uid);
     
     int getUidForSharedUser(String sharedUserName);
-    
+
+    int getFlagsForUid(int uid);
+
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
 
     List<ResolveInfo> queryIntentActivities(in Intent intent, 
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index dc2b0ae..2dd0e44 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1154,8 +1154,8 @@
             throw new SecurityException(msg);
         }
 
-        boolean abort = !mService.mIntentFirewall.checkStartActivity(intent,
-                callerApp==null?null:callerApp.info, callingUid, callingPid, resolvedType, aInfo);
+        boolean abort = !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
+                callingPid, resolvedType, aInfo);
 
         if (mService.mController != null) {
             try {
diff --git a/services/java/com/android/server/firewall/AndFilter.java b/services/java/com/android/server/firewall/AndFilter.java
index e4276d0..8894951 100644
--- a/services/java/com/android/server/firewall/AndFilter.java
+++ b/services/java/com/android/server/firewall/AndFilter.java
@@ -25,10 +25,10 @@
 
 class AndFilter extends FilterList {
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp) {
         for (int i=0; i<children.size(); i++) {
-            if (!children.get(i).matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
+            if (!children.get(i).matches(ifw, intent, callerUid, callerPid, resolvedType,
                     resolvedApp)) {
                 return false;
             }
diff --git a/services/java/com/android/server/firewall/CategoryFilter.java b/services/java/com/android/server/firewall/CategoryFilter.java
index 4938cb8..e609b1e 100644
--- a/services/java/com/android/server/firewall/CategoryFilter.java
+++ b/services/java/com/android/server/firewall/CategoryFilter.java
@@ -34,8 +34,8 @@
     }
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp) {
         Set<String> categories = intent.getCategories();
         if (categories == null) {
             return false;
diff --git a/services/java/com/android/server/firewall/Filter.java b/services/java/com/android/server/firewall/Filter.java
index 0e783e8..740cbe97 100644
--- a/services/java/com/android/server/firewall/Filter.java
+++ b/services/java/com/android/server/firewall/Filter.java
@@ -25,15 +25,11 @@
      *
      * @param ifw The IntentFirewall instance
      * @param intent The intent being started/bound/broadcast
-     * @param callerApp An ApplicationInfo of an application in the caller's process. This may not
-     *                  be the specific app that is actually sending the intent. This also may be
-     *                  null, if the caller is the system process, or an unrecognized process (e.g.
-     *                  am start)
-     * @param callerUid
-     * @param callerPid
+     * @param callerUid The uid of the caller
+     * @param callerPid The pid of the caller
      * @param resolvedType The resolved mime type of the intent
      * @param resolvedApp The application that contains the resolved component that the intent is
      */
-    boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp);
+    boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp);
 }
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
index 58a0324..fc31023 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.os.Environment;
@@ -46,7 +45,7 @@
 import java.util.List;
 
 public class IntentFirewall {
-    private static final String TAG = "IntentFirewall";
+    static final String TAG = "IntentFirewall";
 
     // e.g. /data/system/ifw or /data/secure/system/ifw
     private static final File RULES_DIR = new File(Environment.getSystemSecureDirectory(), "ifw");
@@ -119,15 +118,15 @@
      * This is called from ActivityManager to check if a start activity intent should be allowed.
      * It is assumed the caller is already holding the global ActivityManagerService lock.
      */
-    public boolean checkStartActivity(Intent intent, ApplicationInfo callerApp, int callerUid,
-            int callerPid, String resolvedType, ActivityInfo resolvedActivity) {
+    public boolean checkStartActivity(Intent intent, int callerUid, int callerPid,
+            String resolvedType, ActivityInfo resolvedActivity) {
         List<Rule> matchingRules = mActivityResolver.queryIntent(intent, resolvedType, false, 0);
         boolean log = false;
         boolean block = false;
 
         for (int i=0; i< matchingRules.size(); i++) {
             Rule rule = matchingRules.get(i);
-            if (rule.matches(this, intent, callerApp, callerUid, callerPid, resolvedType,
+            if (rule.matches(this, intent, callerUid, callerPid, resolvedType,
                     resolvedActivity.applicationInfo)) {
                 block |= rule.getBlock();
                 log |= rule.getLog();
@@ -504,4 +503,5 @@
             return false;
         }
     }
+
 }
diff --git a/services/java/com/android/server/firewall/NotFilter.java b/services/java/com/android/server/firewall/NotFilter.java
index f0fc337..327eb59 100644
--- a/services/java/com/android/server/firewall/NotFilter.java
+++ b/services/java/com/android/server/firewall/NotFilter.java
@@ -32,10 +32,9 @@
     }
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-        return !mChild.matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
-                resolvedApp);
+    public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp) {
+        return !mChild.matches(ifw, intent, callerUid, callerPid, resolvedType, resolvedApp);
     }
 
     public static final FilterFactory FACTORY = new FilterFactory("not") {
diff --git a/services/java/com/android/server/firewall/OrFilter.java b/services/java/com/android/server/firewall/OrFilter.java
index 72db31e..23c0fe0 100644
--- a/services/java/com/android/server/firewall/OrFilter.java
+++ b/services/java/com/android/server/firewall/OrFilter.java
@@ -25,10 +25,10 @@
 
 class OrFilter extends FilterList {
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp) {
         for (int i=0; i<children.size(); i++) {
-            if (children.get(i).matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
+            if (children.get(i).matches(ifw, intent, callerUid, callerPid, resolvedType,
                     resolvedApp)) {
                 return true;
             }
diff --git a/services/java/com/android/server/firewall/PortFilter.java b/services/java/com/android/server/firewall/PortFilter.java
index fe7e085..ac4504f 100644
--- a/services/java/com/android/server/firewall/PortFilter.java
+++ b/services/java/com/android/server/firewall/PortFilter.java
@@ -41,8 +41,8 @@
     }
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp) {
         int port = -1;
         Uri uri = intent.getData();
         if (uri != null) {
diff --git a/services/java/com/android/server/firewall/SenderFilter.java b/services/java/com/android/server/firewall/SenderFilter.java
index 58bdd73..3d7b450 100644
--- a/services/java/com/android/server/firewall/SenderFilter.java
+++ b/services/java/com/android/server/firewall/SenderFilter.java
@@ -16,9 +16,13 @@
 
 package com.android.server.firewall;
 
+import android.app.AppGlobals;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.os.Process;
+import android.os.RemoteException;
+import android.util.Slog;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -32,15 +36,21 @@
     private static final String VAL_SYSTEM_OR_SIGNATURE = "system|signature";
     private static final String VAL_USER_ID = "userId";
 
-    static boolean isSystemApp(ApplicationInfo callerApp, int callerUid, int callerPid) {
-        if (callerUid == Process.SYSTEM_UID ||
-                callerPid == Process.myPid()) {
+    static boolean isPrivilegedApp(int callerUid, int callerPid) {
+        if (callerUid == Process.SYSTEM_UID || callerUid == 0 ||
+                callerPid == Process.myPid() || callerPid == 0) {
             return true;
         }
-        if (callerApp == null) {
-            return false;
+
+        IPackageManager pm = AppGlobals.getPackageManager();
+        try {
+            return (pm.getFlagsForUid(callerUid) & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+        } catch (RemoteException ex) {
+            Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
+                    ex);
         }
-        return (callerApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+
+        return false;
     }
 
     public static final FilterFactory FACTORY = new FilterFactory("sender") {
@@ -67,40 +77,33 @@
 
     private static final Filter SIGNATURE = new Filter() {
         @Override
-        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-            if (callerApp == null) {
-                return false;
-            }
+        public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+                String resolvedType, ApplicationInfo resolvedApp) {
             return ifw.signaturesMatch(callerUid, resolvedApp.uid);
         }
     };
 
     private static final Filter SYSTEM = new Filter() {
         @Override
-        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-            if (callerApp == null) {
-                // if callerApp is null, the caller is the system process
-                return false;
-            }
-            return isSystemApp(callerApp, callerUid, callerPid);
+        public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+                String resolvedType,  ApplicationInfo resolvedApp) {
+            return isPrivilegedApp(callerUid, callerPid);
         }
     };
 
     private static final Filter SYSTEM_OR_SIGNATURE = new Filter() {
         @Override
-        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-            return isSystemApp(callerApp, callerUid, callerPid) ||
+        public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+                String resolvedType, ApplicationInfo resolvedApp) {
+            return isPrivilegedApp(callerUid, callerPid) ||
                     ifw.signaturesMatch(callerUid, resolvedApp.uid);
         }
     };
 
     private static final Filter USER_ID = new Filter() {
         @Override
-        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+                String resolvedType, ApplicationInfo resolvedApp) {
             // This checks whether the caller is either the system process, or has the same user id
             // I.e. the same app, or an app that uses the same shared user id.
             // This is the same set of applications that would be able to access the component if
diff --git a/services/java/com/android/server/firewall/SenderPermissionFilter.java b/services/java/com/android/server/firewall/SenderPermissionFilter.java
index 310da20..a88ceaf 100644
--- a/services/java/com/android/server/firewall/SenderPermissionFilter.java
+++ b/services/java/com/android/server/firewall/SenderPermissionFilter.java
@@ -33,8 +33,8 @@
     }
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+    public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp) {
         // We assume the component is exported here. If the component is not exported, then
         // ActivityManager would only resolve to this component for callers from the same uid.
         // In this case, it doesn't matter whether the component is exported or not.
diff --git a/services/java/com/android/server/firewall/StringFilter.java b/services/java/com/android/server/firewall/StringFilter.java
index ed5d3f3..3fa09f3 100644
--- a/services/java/com/android/server/firewall/StringFilter.java
+++ b/services/java/com/android/server/firewall/StringFilter.java
@@ -119,9 +119,9 @@
     protected abstract boolean matchesValue(String value);
 
     @Override
-    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
-            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
-        String value = mValueProvider.getValue(intent, callerApp, resolvedType, resolvedApp);
+    public boolean matches(IntentFirewall ifw, Intent intent, int callerUid, int callerPid,
+            String resolvedType, ApplicationInfo resolvedApp) {
+        String value = mValueProvider.getValue(intent, resolvedType, resolvedApp);
         return matchesValue(value);
     }
 
@@ -135,8 +135,8 @@
             return StringFilter.readFromXml(this, parser);
         }
 
-        public abstract String getValue(Intent intent, ApplicationInfo callerApp,
-                String resolvedType, ApplicationInfo resolvedApp);
+        public abstract String getValue(Intent intent, String resolvedType,
+                ApplicationInfo resolvedApp);
     }
 
     private static class EqualsFilter extends StringFilter {
@@ -230,8 +230,7 @@
 
     public static final ValueProvider COMPONENT = new ValueProvider("component") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             ComponentName cn = intent.getComponent();
             if (cn != null) {
                 return cn.flattenToString();
@@ -242,8 +241,7 @@
 
     public static final ValueProvider COMPONENT_NAME = new ValueProvider("component-name") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             ComponentName cn = intent.getComponent();
             if (cn != null) {
                 return cn.getClassName();
@@ -254,8 +252,7 @@
 
     public static final ValueProvider COMPONENT_PACKAGE = new ValueProvider("component-package") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             ComponentName cn = intent.getComponent();
             if (cn != null) {
                 return cn.getPackageName();
@@ -266,16 +263,14 @@
 
     public static final FilterFactory ACTION = new ValueProvider("action") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             return intent.getAction();
         }
     };
 
     public static final ValueProvider DATA = new ValueProvider("data") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.toString();
@@ -286,16 +281,14 @@
 
     public static final ValueProvider MIME_TYPE = new ValueProvider("mime-type") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             return resolvedType;
         }
     };
 
     public static final ValueProvider SCHEME = new ValueProvider("scheme") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.getScheme();
@@ -306,8 +299,7 @@
 
     public static final ValueProvider SSP = new ValueProvider("scheme-specific-part") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.getSchemeSpecificPart();
@@ -318,8 +310,7 @@
 
     public static final ValueProvider HOST = new ValueProvider("host") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.getHost();
@@ -330,8 +321,7 @@
 
     public static final ValueProvider PATH = new ValueProvider("path") {
         @Override
-        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
-                ApplicationInfo resolvedApp) {
+        public String getValue(Intent intent, String resolvedType, ApplicationInfo resolvedApp) {
             Uri data = intent.getData();
             if (data != null) {
                 return data.getPath();
diff --git a/services/java/com/android/server/pm/GrantedPermissions.java b/services/java/com/android/server/pm/GrantedPermissions.java
index c7629b9..14258a4 100644
--- a/services/java/com/android/server/pm/GrantedPermissions.java
+++ b/services/java/com/android/server/pm/GrantedPermissions.java
@@ -44,6 +44,7 @@
     void setFlags(int pkgFlags) {
         this.pkgFlags = pkgFlags
                 & (ApplicationInfo.FLAG_SYSTEM
+                        | ApplicationInfo.FLAG_PRIVILEGED
                         | ApplicationInfo.FLAG_FORWARD_LOCK
                         | ApplicationInfo.FLAG_EXTERNAL_STORAGE);
     }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index fea7fe7c..80e20a5 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -2574,6 +2574,20 @@
         }
     }
 
+    public int getFlagsForUid(int uid) {
+        synchronized (mPackages) {
+            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+            if (obj instanceof SharedUserSetting) {
+                final SharedUserSetting sus = (SharedUserSetting) obj;
+                return sus.pkgFlags;
+            } else if (obj instanceof PackageSetting) {
+                final PackageSetting ps = (PackageSetting) obj;
+                return ps.pkgFlags;
+            }
+        }
+        return 0;
+    }
+
     @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
@@ -4058,8 +4072,7 @@
             }
 
             if (pkg.mSharedUserId != null) {
-                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId,
-                        pkg.applicationInfo.flags, true);
+                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
                 if (suid == null) {
                     Slog.w(TAG, "Creating application package " + pkg.packageName
                             + " for shared user failed");
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index e6611f0..163536a 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -594,7 +594,7 @@
                         "Package " + p.name + " was user "
                         + p.sharedUser + " but is now " + sharedUser
                         + "; I am not changing its files so it will probably fail!");
-                p.sharedUser.packages.remove(p);
+                p.sharedUser.removePackage(p);
             } else if (p.appId != sharedUser.userId) {
                 PackageManagerService.reportSettingsProblem(Log.ERROR,
                     "Package " + p.name + " was user id " + p.appId
@@ -603,7 +603,7 @@
                     + "; I am not changing its files so it will probably fail!");
             }
 
-            sharedUser.packages.add(p);
+            sharedUser.addPackage(p);
             p.sharedUser = sharedUser;
             p.appId = sharedUser.userId;
         }
@@ -663,7 +663,7 @@
         if (p != null) {
             mPackages.remove(name);
             if (p.sharedUser != null) {
-                p.sharedUser.packages.remove(p);
+                p.sharedUser.removePackage(p);
                 if (p.sharedUser.packages.size() == 0) {
                     mSharedUsers.remove(p.sharedUser.name);
                     removeUserIdLPw(p.sharedUser.userId);
@@ -681,8 +681,8 @@
         final PackageSetting p = mPackages.get(name);
         if (p != null) {
             if (p.sharedUser != null) {
-                p.sharedUser.packages.remove(p);
-                p.sharedUser.packages.add(newp);
+                p.sharedUser.removePackage(p);
+                p.sharedUser.addPackage(newp);
             } else {
                 replaceUserIdLPw(p.appId, newp);
             }
diff --git a/services/java/com/android/server/pm/SharedUserSetting.java b/services/java/com/android/server/pm/SharedUserSetting.java
index 76826ea..ca1eeea 100644
--- a/services/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/java/com/android/server/pm/SharedUserSetting.java
@@ -26,12 +26,16 @@
 
     int userId;
 
+    // flags that are associated with this uid, regardless of any package flags
+    int uidFlags;
+
     final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
 
     final PackageSignatures signatures = new PackageSignatures();
 
     SharedUserSetting(String _name, int _pkgFlags) {
         super(_pkgFlags);
+        uidFlags =  _pkgFlags;
         name = _name;
     }
 
@@ -40,4 +44,23 @@
         return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
                 + name + "/" + userId + "}";
     }
+
+    void removePackage(PackageSetting packageSetting) {
+        if (packages.remove(packageSetting)) {
+            // recalculate the pkgFlags for this shared user if needed
+            if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
+                int aggregatedFlags = uidFlags;
+                for (PackageSetting ps : packages) {
+                    aggregatedFlags |= ps.pkgFlags;
+                }
+                setFlags(aggregatedFlags);
+            }
+        }
+    }
+
+    void addPackage(PackageSetting packageSetting) {
+        if (packages.add(packageSetting)) {
+            setFlags(this.pkgFlags | packageSetting.pkgFlags);
+        }
+    }
 }