/* * Copyright (C) 2006 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 static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import static com.android.internal.util.ArrayUtils.appendInt; import static com.android.internal.util.ArrayUtils.removeInt; import static libcore.io.OsConstants.S_IRWXU; import static libcore.io.OsConstants.S_IRGRP; import static libcore.io.OsConstants.S_IXGRP; import static libcore.io.OsConstants.S_IROTH; import static libcore.io.OsConstants.S_IXOTH; import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; import com.android.server.EventLogTags; import com.android.server.IntentResolver; import com.android.server.ServiceThread; import com.android.server.LocalServices; import com.android.server.Watchdog; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.admin.IDevicePolicyManager; import android.app.backup.IBackupManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.ServiceConnection; import android.content.IntentSender.SendIntentException; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ContainerEncryptionParams; import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageCleanItem; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageStats; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.content.pm.ManifestDigest; import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.SELinux; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.Environment.UserEnvironment; import android.os.UserManager; import android.security.KeyStore; import android.security.SystemKeyStore; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; import android.util.LogPrinter; import android.util.PrintStreamPrinter; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; import android.view.Display; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintWriter; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.cert.CertificateException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import libcore.io.ErrnoException; import libcore.io.IoUtils; import libcore.io.Libcore; import libcore.io.StructStat; import com.android.internal.R; import com.android.server.storage.DeviceStorageMonitorInternal; /** * Keep track of all those .apks everywhere. * * This is very central to the platform's security; please run the unit * tests whenever making modifications here: * mmm frameworks/base/tests/AndroidTests adb install -r -f out/target/product/passion/data/app/AndroidTests.apk adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner * * {@hide} */ public class PackageManagerService extends IPackageManager.Stub { static final String TAG = "PackageManager"; static final boolean DEBUG_SETTINGS = false; static final boolean DEBUG_PREFERRED = false; static final boolean DEBUG_UPGRADE = false; private static final boolean DEBUG_INSTALL = false; private static final boolean DEBUG_REMOVE = false; private static final boolean DEBUG_BROADCASTS = false; private static final boolean DEBUG_SHOW_INFO = false; private static final boolean DEBUG_PACKAGE_INFO = false; private static final boolean DEBUG_INTENT_MATCHING = false; private static final boolean DEBUG_PACKAGE_SCANNING = false; private static final boolean DEBUG_APP_DIR_OBSERVER = false; private static final boolean DEBUG_VERIFY = false; private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; private static final int NFC_UID = Process.NFC_UID; private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID; private static final int SHELL_UID = Process.SHELL_UID; private static final boolean GET_CERTIFICATES = true; private static final int REMOVE_EVENTS = FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM; private static final int ADD_EVENTS = FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO; private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS; // Suffix used during package installation when copying/moving // package apks to install directory. private static final String INSTALL_PACKAGE_SUFFIX = "-"; static final int SCAN_MONITOR = 1<<0; static final int SCAN_NO_DEX = 1<<1; static final int SCAN_FORCE_DEX = 1<<2; static final int SCAN_UPDATE_SIGNATURE = 1<<3; static final int SCAN_NEW_INSTALL = 1<<4; static final int SCAN_NO_PATHS = 1<<5; static final int SCAN_UPDATE_TIME = 1<<6; static final int SCAN_DEFER_DEX = 1<<7; static final int SCAN_BOOTING = 1<<8; static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<9; static final int REMOVE_CHATTY = 1<<16; /** * Timeout (in milliseconds) after which the watchdog should declare that * our handler thread is wedged. The usual default for such things is one * minute but we sometimes do very lengthy I/O operations on this thread, * such as installing multi-gigabyte applications, so ours needs to be longer. */ private static final long WATCHDOG_TIMEOUT = 1000*60*10; // ten minutes /** * Whether verification is enabled by default. */ private static final boolean DEFAULT_VERIFY_ENABLE = true; /** * The default maximum time to wait for the verification agent to return in * milliseconds. */ private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000; /** * The default response for package verification timeout. * * This can be either PackageManager.VERIFICATION_ALLOW or * PackageManager.VERIFICATION_REJECT. */ private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW; static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer"; static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService"); private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; private static final String LIB_DIR_NAME = "lib"; static final String mTempContainerPrefix = "smdl2tmp"; final ServiceThread mHandlerThread; final PackageHandler mHandler; final int mSdkVersion = Build.VERSION.SDK_INT; final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME) ? null : Build.VERSION.CODENAME; final Context mContext; final boolean mFactoryTest; final boolean mOnlyCore; final boolean mNoDexOpt; final DisplayMetrics mMetrics; final int mDefParseFlags; final String[] mSeparateProcesses; // This is where all application persistent data goes. final File mAppDataDir; // This is where all application persistent data goes for secondary users. final File mUserAppDataDir; /** The location for ASEC container files on internal storage. */ final String mAsecInternalPath; // This is the object monitoring the framework dir. final FileObserver mFrameworkInstallObserver; // This is the object monitoring the system app dir. final FileObserver mSystemInstallObserver; // This is the object monitoring the privileged system app dir. final FileObserver mPrivilegedInstallObserver; // This is the object monitoring the system app dir. final FileObserver mVendorInstallObserver; // This is the object monitoring mAppInstallDir. final FileObserver mAppInstallObserver; // This is the object monitoring mDrmAppPrivateInstallDir. final FileObserver mDrmAppInstallObserver; // Used for privilege escalation. MUST NOT BE CALLED WITH mPackages // LOCK HELD. Can be called with mInstallLock held. final Installer mInstaller; final File mAppInstallDir; /** * Directory to which applications installed internally have native * libraries copied. */ private File mAppLibInstallDir; // Directory containing the private parts (e.g. code and non-resource assets) of forward-locked // apps. final File mDrmAppPrivateInstallDir; // ---------------------------------------------------------------- // Lock for state used when installing and doing other long running // operations. Methods that must be called with this lock held have // the prefix "LI". final Object mInstallLock = new Object(); // These are the directories in the 3rd party applications installed dir // that we have currently loaded packages from. Keys are the application's // installed zip file (absolute codePath), and values are Package. final HashMap mAppDirs = new HashMap(); // Information for the parser to write more useful error messages. int mLastScanError; // ---------------------------------------------------------------- // Keys are String (package name), values are Package. This also serves // as the lock for the global state. Methods that must be called with // this lock held have the prefix "LP". final HashMap mPackages = new HashMap(); final Settings mSettings; boolean mRestoredSettings; // Group-ids that are given to all packages as read from etc/permissions/*.xml. int[] mGlobalGids; // These are the built-in uid -> permission mappings that were read from the // etc/permissions.xml file. final SparseArray> mSystemPermissions = new SparseArray>(); static final class SharedLibraryEntry { final String path; final String apk; SharedLibraryEntry(String _path, String _apk) { path = _path; apk = _apk; } } // These are the built-in shared libraries that were read from the // etc/permissions.xml file. final HashMap mSharedLibraries = new HashMap(); // Temporary for building the final shared libraries for an .apk. String[] mTmpSharedLibraries = null; // These are the features this devices supports that were read from the // etc/permissions.xml file. final HashMap mAvailableFeatures = new HashMap(); // If mac_permissions.xml was found for seinfo labeling. boolean mFoundPolicyFile; // All available activities, for your resolving pleasure. final ActivityIntentResolver mActivities = new ActivityIntentResolver(); // All available receivers, for your resolving pleasure. final ActivityIntentResolver mReceivers = new ActivityIntentResolver(); // All available services, for your resolving pleasure. final ServiceIntentResolver mServices = new ServiceIntentResolver(); // All available providers, for your resolving pleasure. final ProviderIntentResolver mProviders = new ProviderIntentResolver(); // Mapping from provider base names (first directory in content URI codePath) // to the provider information. final HashMap mProvidersByAuthority = new HashMap(); // Mapping from instrumentation class names to info about them. final HashMap mInstrumentation = new HashMap(); // Mapping from permission names to info about them. final HashMap mPermissionGroups = new HashMap(); // Packages whose data we have transfered into another package, thus // should no longer exist. final HashSet mTransferedPackages = new HashSet(); // Broadcast actions that are only available to the system. final HashSet mProtectedBroadcasts = new HashSet(); /** List of packages waiting for verification. */ final SparseArray mPendingVerification = new SparseArray(); HashSet mDeferredDexOpt = null; /** Token for keys in mPendingVerification. */ private int mPendingVerificationToken = 0; boolean mSystemReady; boolean mSafeMode; boolean mHasSystemUidErrors; ApplicationInfo mAndroidApplication; final ActivityInfo mResolveActivity = new ActivityInfo(); final ResolveInfo mResolveInfo = new ResolveInfo(); ComponentName mResolveComponentName; PackageParser.Package mPlatformPackage; ComponentName mCustomResolverComponentName; boolean mResolverReplaced = false; // Set of pending broadcasts for aggregating enable/disable of components. static class PendingPackageBroadcasts { // for each user id, a map of components within that package> final SparseArray>> mUidMap; public PendingPackageBroadcasts() { mUidMap = new SparseArray>>(2); } public ArrayList get(int userId, String packageName) { HashMap> packages = getOrAllocate(userId); return packages.get(packageName); } public void put(int userId, String packageName, ArrayList components) { HashMap> packages = getOrAllocate(userId); packages.put(packageName, components); } public void remove(int userId, String packageName) { HashMap> packages = mUidMap.get(userId); if (packages != null) { packages.remove(packageName); } } public void remove(int userId) { mUidMap.remove(userId); } public int userIdCount() { return mUidMap.size(); } public int userIdAt(int n) { return mUidMap.keyAt(n); } public HashMap> packagesForUserId(int userId) { return mUidMap.get(userId); } public int size() { // total number of pending broadcast entries across all userIds int num = 0; for (int i = 0; i< mUidMap.size(); i++) { num += mUidMap.valueAt(i).size(); } return num; } public void clear() { mUidMap.clear(); } private HashMap> getOrAllocate(int userId) { HashMap> map = mUidMap.get(userId); if (map == null) { map = new HashMap>(); mUidMap.put(userId, map); } return map; } } final PendingPackageBroadcasts mPendingBroadcasts = new PendingPackageBroadcasts(); // Service Connection to remote media container service to copy // package uri's from external media onto secure containers // or internal storage. private IMediaContainerService mContainerService = null; static final int SEND_PENDING_BROADCAST = 1; static final int MCS_BOUND = 3; static final int END_COPY = 4; static final int INIT_COPY = 5; static final int MCS_UNBIND = 6; static final int START_CLEANING_PACKAGE = 7; static final int FIND_INSTALL_LOC = 8; static final int POST_INSTALL = 9; static final int MCS_RECONNECT = 10; static final int MCS_GIVE_UP = 11; static final int UPDATED_MEDIA_STATUS = 12; static final int WRITE_SETTINGS = 13; static final int WRITE_PACKAGE_RESTRICTIONS = 14; static final int PACKAGE_VERIFIED = 15; static final int CHECK_PENDING_VERIFICATION = 16; static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds // Delay time in millisecs static final int BROADCAST_DELAY = 10 * 1000; static UserManagerService sUserManager; // Stores a list of users whose package restrictions file needs to be updated private HashSet mDirtyUsers = new HashSet(); final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); class DefaultContainerConnection implements ServiceConnection { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected"); IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs)); } public void onServiceDisconnected(ComponentName name) { if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected"); } }; // Recordkeeping of restore-after-install operations that are currently in flight // between the Package Manager and the Backup Manager class PostInstallData { public InstallArgs args; public PackageInstalledInfo res; PostInstallData(InstallArgs _a, PackageInstalledInfo _r) { args = _a; res = _r; } }; final SparseArray mRunningInstalls = new SparseArray(); int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows private final String mRequiredVerifierPackage; class PackageHandler extends Handler { private boolean mBound = false; final ArrayList mPendingInstalls = new ArrayList(); private boolean connectToService() { if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" + " DefaultContainerService"); Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mBound = true; return true; } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return false; } private void disconnectService() { mContainerService = null; mBound = false; Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); mContext.unbindService(mDefContainerConn); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } PackageHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { try { doHandleMessage(msg); } finally { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } } void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj; int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params); // If a bind was already initiated we dont really // need to do anything. The pending install // will be processed later on. if (!mBound) { // If this is the only one pending we might // have to bind to the service again. if (!connectToService()) { Slog.e(TAG, "Failed to bind to media container service"); params.serviceError(); return; } else { // Once we bind to the service, the first // pending request will be processed. mPendingInstalls.add(idx, params); } } else { mPendingInstalls.add(idx, params); // Already bound to the service. Just make // sure we trigger off processing the first request. if (idx == 0) { mHandler.sendEmptyMessage(MCS_BOUND); } } break; } case MCS_BOUND: { if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound"); if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; } if (mContainerService == null) { // Something seriously wrong. Bail out Slog.e(TAG, "Cannot bind to media container service"); for (HandlerParams params : mPendingInstalls) { // Indicate service bind error params.serviceError(); } mPendingInstalls.clear(); } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0); if (params != null) { if (params.startCopy()) { // We are done... look for more work or to // go idle. if (DEBUG_SD_INSTALL) Log.i(TAG, "Checking for more work or unbind..."); // Delete pending install if (mPendingInstalls.size() > 0) { mPendingInstalls.remove(0); } if (mPendingInstalls.size() == 0) { if (mBound) { if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting delayed MCS_UNBIND"); removeMessages(MCS_UNBIND); Message ubmsg = obtainMessage(MCS_UNBIND); // Unbind after a little delay, to avoid // continual thrashing. sendMessageDelayed(ubmsg, 10000); } } else { // There are more pending requests in queue. // Just post MCS_BOUND message to trigger processing // of next pending install. if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting MCS_BOUND for next woek"); mHandler.sendEmptyMessage(MCS_BOUND); } } } } else { // Should never happen ideally. Slog.w(TAG, "Empty queue"); } break; } case MCS_RECONNECT: { if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect"); if (mPendingInstalls.size() > 0) { if (mBound) { disconnectService(); } if (!connectToService()) { Slog.e(TAG, "Failed to bind to media container service"); for (HandlerParams params : mPendingInstalls) { // Indicate service bind error params.serviceError(); } mPendingInstalls.clear(); } } break; } case MCS_UNBIND: { // If there is no actual work left, then time to unbind. if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind"); if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) { if (mBound) { if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()"); disconnectService(); } } else if (mPendingInstalls.size() > 0) { // There are more pending requests in queue. // Just post MCS_BOUND message to trigger processing // of next pending install. mHandler.sendEmptyMessage(MCS_BOUND); } break; } case MCS_GIVE_UP: { if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries"); mPendingInstalls.remove(0); break; } case SEND_PENDING_BROADCAST: { String packages[]; ArrayList components[]; int size = 0; int uids[]; Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mPackages) { if (mPendingBroadcasts == null) { return; } size = mPendingBroadcasts.size(); if (size <= 0) { // Nothing to be done. Just return return; } packages = new String[size]; components = new ArrayList[size]; uids = new int[size]; int i = 0; // filling out the above arrays for (int n = 0; n < mPendingBroadcasts.userIdCount(); n++) { int packageUserId = mPendingBroadcasts.userIdAt(n); Iterator>> it = mPendingBroadcasts.packagesForUserId(packageUserId) .entrySet().iterator(); while (it.hasNext() && i < size) { Map.Entry> ent = it.next(); packages[i] = ent.getKey(); components[i] = ent.getValue(); PackageSetting ps = mSettings.mPackages.get(ent.getKey()); uids[i] = (ps != null) ? UserHandle.getUid(packageUserId, ps.appId) : -1; i++; } } size = i; mPendingBroadcasts.clear(); } // Send broadcasts for (int i = 0; i < size; i++) { sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); break; } case START_CLEANING_PACKAGE: { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); final String packageName = (String)msg.obj; final int userId = msg.arg1; final boolean andCode = msg.arg2 != 0; synchronized (mPackages) { if (userId == UserHandle.USER_ALL) { int[] users = sUserManager.getUserIds(); for (int user : users) { mSettings.addPackageToCleanLPw( new PackageCleanItem(user, packageName, andCode)); } } else { mSettings.addPackageToCleanLPw( new PackageCleanItem(userId, packageName, andCode)); } } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); startCleaningPackages(); } break; case POST_INSTALL: { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); PostInstallData data = mRunningInstalls.get(msg.arg1); mRunningInstalls.delete(msg.arg1); boolean deleteOld = false; if (data != null) { InstallArgs args = data.args; PackageInstalledInfo res = data.res; if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { res.removedInfo.sendBroadcast(false, true, false); Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, res.uid); // Determine the set of users who are adding this // package for the first time vs. those who are seeing // an update. int[] firstUsers; int[] updateUsers = new int[0]; if (res.origUsers == null || res.origUsers.length == 0) { firstUsers = res.newUsers; } else { firstUsers = new int[0]; for (int i=0; i AVAILABLE"); } int[] uidArray = new int[] { res.pkg.applicationInfo.uid }; ArrayList pkgList = new ArrayList(1); pkgList.add(res.pkg.applicationInfo.packageName); sendResourcesChangedBroadcast(true, true, pkgList,uidArray, null); } } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now deleteOld = true; } // Log current value of "unknown sources" setting EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED, getUnknownSourcesSettings()); } // Force a gc to clear up things Runtime.getRuntime().gc(); // We delete after a gc for applications on sdcard. if (deleteOld) { synchronized (mInstallLock) { res.removedInfo.args.doPostDeleteLI(true); } } if (args.observer != null) { try { args.observer.packageInstalled(res.name, res.returnCode); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } } } else { Slog.e(TAG, "Bogus post-install token " + msg.arg1); } } break; case UPDATED_MEDIA_STATUS: { if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS"); boolean reportStatus = msg.arg1 == 1; boolean doGc = msg.arg2 == 1; if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc); if (doGc) { // Force a gc to clear up stale containers. Runtime.getRuntime().gc(); } if (msg.obj != null) { @SuppressWarnings("unchecked") Set args = (Set) msg.obj; if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers"); // Unload containers unloadAllContainers(args); } if (reportStatus) { try { if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back"); PackageHelper.getMountService().finishMediaUpdate(); } catch (RemoteException e) { Log.e(TAG, "MountService not running?"); } } } break; case WRITE_SETTINGS: { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mPackages) { removeMessages(WRITE_SETTINGS); removeMessages(WRITE_PACKAGE_RESTRICTIONS); mSettings.writeLPr(); mDirtyUsers.clear(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; case WRITE_PACKAGE_RESTRICTIONS: { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mPackages) { removeMessages(WRITE_PACKAGE_RESTRICTIONS); for (int userId : mDirtyUsers) { mSettings.writePackageRestrictionsLPr(userId); } mDirtyUsers.clear(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; case CHECK_PENDING_VERIFICATION: { final int verificationId = msg.arg1; final PackageVerificationState state = mPendingVerification.get(verificationId); if ((state != null) && !state.timeoutExtended()) { final InstallArgs args = state.getInstallArgs(); Slog.i(TAG, "Verification timed out for " + args.packageURI.toString()); mPendingVerification.remove(verificationId); int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) { Slog.i(TAG, "Continuing with installation of " + args.packageURI.toString()); state.setVerifierResponse(Binder.getCallingUid(), PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT); broadcastPackageVerified(verificationId, args.packageURI, PackageManager.VERIFICATION_ALLOW, state.getInstallArgs().getUser()); try { ret = args.copyApk(mContainerService, true); } catch (RemoteException e) { Slog.e(TAG, "Could not contact the ContainerService"); } } else { broadcastPackageVerified(verificationId, args.packageURI, PackageManager.VERIFICATION_REJECT, state.getInstallArgs().getUser()); } processPendingInstall(args, ret); mHandler.sendEmptyMessage(MCS_UNBIND); } break; } case PACKAGE_VERIFIED: { final int verificationId = msg.arg1; final PackageVerificationState state = mPendingVerification.get(verificationId); if (state == null) { Slog.w(TAG, "Invalid verification token " + verificationId + " received"); break; } final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj; state.setVerifierResponse(response.callerUid, response.code); if (state.isVerificationComplete()) { mPendingVerification.remove(verificationId); final InstallArgs args = state.getInstallArgs(); int ret; if (state.isInstallAllowed()) { ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; broadcastPackageVerified(verificationId, args.packageURI, response.code, state.getInstallArgs().getUser()); try { ret = args.copyApk(mContainerService, true); } catch (RemoteException e) { Slog.e(TAG, "Could not contact the ContainerService"); } } else { ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; } processPendingInstall(args, ret); mHandler.sendEmptyMessage(MCS_UNBIND); } break; } } } } void scheduleWriteSettingsLocked() { if (!mHandler.hasMessages(WRITE_SETTINGS)) { mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY); } } void scheduleWritePackageRestrictionsLocked(int userId) { if (!sUserManager.exists(userId)) return; mDirtyUsers.add(userId); if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) { mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY); } } public static final IPackageManager main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); ServiceManager.addService("package", m); return m; } static String[] splitString(String str, char sep) { int count = 1; int i = 0; while ((i=str.indexOf(sep, i)) >= 0) { count++; i++; } String[] res = new String[count]; i=0; count = 0; int lastI=0; while ((i=str.indexOf(sep, i)) >= 0) { res[count] = str.substring(lastI, i); count++; i++; lastI = i; } res[count] = str.substring(lastI, str.length()); return res; } private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) { DisplayManager displayManager = (DisplayManager) context.getSystemService( Context.DISPLAY_SERVICE); displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics); } public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis()); if (mSdkVersion <= 0) { Slog.w(TAG, "**** ro.build.version.sdk not set!"); } mContext = context; mFactoryTest = factoryTest; mOnlyCore = onlyCore; mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type")); mMetrics = new DisplayMetrics(); mSettings = new Settings(context); mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); String separateProcesses = SystemProperties.get("debug.separate_processes"); if (separateProcesses != null && separateProcesses.length() > 0) { if ("*".equals(separateProcesses)) { mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES; mSeparateProcesses = null; Slog.w(TAG, "Running with debug.separate_processes: * (ALL)"); } else { mDefParseFlags = 0; mSeparateProcesses = separateProcesses.split(","); Slog.w(TAG, "Running with debug.separate_processes: " + separateProcesses); } } else { mDefParseFlags = 0; mSeparateProcesses = null; } mInstaller = installer; getDefaultDisplayMetrics(context, mMetrics); synchronized (mInstallLock) { // writer synchronized (mPackages) { mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); File dataDir = Environment.getDataDirectory(); mAppDataDir = new File(dataDir, "data"); mAppInstallDir = new File(dataDir, "app"); mAppLibInstallDir = new File(dataDir, "app-lib"); mAsecInternalPath = new File(dataDir, "app-asec").getPath(); mUserAppDataDir = new File(dataDir, "user"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); sUserManager = new UserManagerService(context, this, mInstallLock, mPackages); readPermissions(); mFoundPolicyFile = SELinuxMMAC.readInstallPolicy(); mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore); String customResolverActivity = Resources.getSystem().getString( R.string.config_customResolverActivity); if (TextUtils.isEmpty(customResolverActivity)) { customResolverActivity = null; } else { mCustomResolverComponentName = ComponentName.unflattenFromString( customResolverActivity); } long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); // Set flag to monitor and not change apk file paths when // scanning install directories. int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING; if (mNoDexOpt) { Slog.w(TAG, "Running ENG build: no pre-dexopt!"); scanMode |= SCAN_NO_DEX; } final HashSet alreadyDexOpted = new HashSet(); /** * Add everything in the in the boot class path to the * list of process files because dexopt will have been run * if necessary during zygote startup. */ String bootClassPath = System.getProperty("java.boot.class.path"); if (bootClassPath != null) { String[] paths = splitString(bootClassPath, ':'); for (int i=0; i 0) { Iterator libs = mSharedLibraries.values().iterator(); while (libs.hasNext()) { String lib = libs.next().path; if (lib == null) { continue; } try { if (dalvik.system.DexFile.isDexOptNeeded(lib)) { alreadyDexOpted.add(lib); mInstaller.dexopt(lib, Process.SYSTEM_UID, true); didDexOpt = true; } } catch (FileNotFoundException e) { Slog.w(TAG, "Library not found: " + lib); } catch (IOException e) { Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? " + e.getMessage()); } } } File frameworkDir = new File(Environment.getRootDirectory(), "framework"); // Gross hack for now: we know this file doesn't contain any // code, so don't dexopt it to avoid the resulting log spew. alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk"); // Gross hack for now: we know this file is only part of // the boot class path for art, so don't dexopt it to // avoid the resulting log spew. alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar"); /** * And there are a number of commands implemented in Java, which * we currently need to do the dexopt on so that they can be * run from a non-root shell. */ String[] frameworkFiles = frameworkDir.list(); if (frameworkFiles != null) { for (int i=0; i possiblyDeletedUpdatedSystemApps = new ArrayList(); if (!mOnlyCore) { Iterator psit = mSettings.mPackages.values().iterator(); while (psit.hasNext()) { PackageSetting ps = psit.next(); /* * If this is not a system app, it can't be a * disable system app. */ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { continue; } /* * If the package is scanned, it's not erased. */ final PackageParser.Package scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { /* * If the system app is both scanned and in the * disabled packages list, then it must have been * added via OTA. Remove it from the currently * scanned package so the previously user-installed * application can be scanned. */ if (mSettings.isDisabledSystemPackageLPr(ps.name)) { Slog.i(TAG, "Expecting better updatd system app for " + ps.name + "; removing system app"); removePackageLI(ps, true); } continue; } if (!mSettings.isDisabledSystemPackageLPr(ps.name)) { psit.remove(); String msg = "System package " + ps.name + " no longer exists; wiping its data"; reportSettingsProblem(Log.WARN, msg); removeDataDirsLI(ps.name); } else { final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name); if (disabledPs.codePath == null || !disabledPs.codePath.exists()) { possiblyDeletedUpdatedSystemApps.add(ps.name); } } } } //look for any incomplete package installations ArrayList deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr(); //clean up list for(int i = 0; i < deletePkgsList.size(); i++) { //clean up here cleanupInstallFailedPackage(deletePkgsList.get(i)); } //delete tmp files deleteTempPackageFiles(); // Remove any shared userIDs that have no associated packages mSettings.pruneSharedUsersLPw(); if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); mAppInstallObserver = new AppDirObserver( mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false); mAppInstallObserver.startWatching(); scanDirLI(mAppInstallDir, 0, scanMode, 0); mDrmAppInstallObserver = new AppDirObserver( mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false); mDrmAppInstallObserver.startWatching(); scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode, 0); /** * Remove disable package settings for any updated system * apps that were removed via an OTA. If they're not a * previously-updated app, remove them completely. * Otherwise, just revoke their system-level permissions. */ for (String deletedAppName : possiblyDeletedUpdatedSystemApps) { PackageParser.Package deletedPkg = mPackages.get(deletedAppName); mSettings.removeDisabledSystemPackageLPw(deletedAppName); String msg; if (deletedPkg == null) { msg = "Updated system package " + deletedAppName + " no longer exists; wiping its data"; removeDataDirsLI(deletedAppName); } else { msg = "Updated system app + " + deletedAppName + " no longer present; removing system privileges for " + deletedAppName; deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName); deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM; } reportSettingsProblem(Log.WARN, msg); } } else { mAppInstallObserver = null; mDrmAppInstallObserver = null; } // Now that we know all of the shared libraries, update all clients to have // the correct library paths. updateAllSharedLibrariesLPw(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); Slog.i(TAG, "Time to scan packages: " + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); // If the platform SDK has changed since the last time we booted, // we need to re-grant app permission to catch any new ones that // appear. This is really a hack, and means that apps can in some // cases get permissions that the user didn't initially explicitly // allow... it would be nice to have some better way to handle // this situation. final boolean regrantPermissions = mSettings.mInternalSdkPlatform != mSdkVersion; if (regrantPermissions) Slog.i(TAG, "Platform changed from " + mSettings.mInternalSdkPlatform + " to " + mSdkVersion + "; regranting permissions for internal storage"); mSettings.mInternalSdkPlatform = mSdkVersion; updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | (regrantPermissions ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL) : 0)); // If this is the first boot, and it is a normal boot, then // we need to initialize the default preferred apps. if (!mRestoredSettings && !onlyCore) { mSettings.readDefaultPreferredAppsLPw(this, 0); } // can downgrade to reader mSettings.writeLPr(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); // Now after opening every single application zip, make sure they // are all flushed. Not really needed, but keeps things nice and // tidy. Runtime.getRuntime().gc(); mRequiredVerifierPackage = getRequiredVerifierLPr(); } // synchronized (mPackages) } // synchronized (mInstallLock) } public boolean isFirstBoot() { return !mRestoredSettings; } public boolean isOnlyCoreApps() { return mOnlyCore; } private String getRequiredVerifierLPr() { final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); final List receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */); String requiredVerifier = null; final int N = receivers.size(); for (int i = 0; i < N; i++) { final ResolveInfo info = receivers.get(i); if (info.activityInfo == null) { continue; } final String packageName = info.activityInfo.packageName; final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) { continue; } final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; if (!gp.grantedPermissions .contains(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT)) { continue; } if (requiredVerifier != null) { throw new RuntimeException("There can be only one required verifier"); } requiredVerifier = packageName; } return requiredVerifier; } @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { try { return super.onTransact(code, data, reply, flags); } catch (RuntimeException e) { if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) { Slog.wtf(TAG, "Package Manager Crash", e); } throw e; } } void cleanupInstallFailedPackage(PackageSetting ps) { Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name); removeDataDirsLI(ps.name); if (ps.codePath != null) { if (!ps.codePath.delete()) { Slog.w(TAG, "Unable to remove old code file: " + ps.codePath); } } if (ps.resourcePath != null) { if (!ps.resourcePath.delete() && !ps.resourcePath.equals(ps.codePath)) { Slog.w(TAG, "Unable to remove old code file: " + ps.resourcePath); } } mSettings.removePackageLPw(ps.name); } void readPermissions() { // Read permissions from .../etc/permission directory. File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions"); if (!libraryDir.exists() || !libraryDir.isDirectory()) { Slog.w(TAG, "No directory " + libraryDir + ", skipping"); return; } if (!libraryDir.canRead()) { Slog.w(TAG, "Directory " + libraryDir + " cannot be read"); return; } // Iterate over the files in the directory and scan .xml files for (File f : libraryDir.listFiles()) { // We'll read platform.xml last if (f.getPath().endsWith("etc/permissions/platform.xml")) { continue; } if (!f.getPath().endsWith(".xml")) { Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring"); continue; } if (!f.canRead()) { Slog.w(TAG, "Permissions library file " + f + " cannot be read"); continue; } readPermissionsFromXml(f); } // Read permissions from .../etc/permissions/platform.xml last so it will take precedence final File permFile = new File(Environment.getRootDirectory(), "etc/permissions/platform.xml"); readPermissionsFromXml(permFile); } private void readPermissionsFromXml(File permFile) { FileReader permReader = null; try { permReader = new FileReader(permFile); } catch (FileNotFoundException e) { Slog.w(TAG, "Couldn't find or open permissions file " + permFile); return; } try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(permReader); XmlUtils.beginDocument(parser, "permissions"); while (true) { XmlUtils.nextElement(parser); if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { break; } String name = parser.getName(); if ("group".equals(name)) { String gidStr = parser.getAttributeValue(null, "gid"); if (gidStr != null) { int gid = Process.getGidForName(gidStr); mGlobalGids = appendInt(mGlobalGids, gid); } else { Slog.w(TAG, " without gid at " + parser.getPositionDescription()); } XmlUtils.skipCurrentTag(parser); continue; } else if ("permission".equals(name)) { String perm = parser.getAttributeValue(null, "name"); if (perm == null) { Slog.w(TAG, " without name at " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } perm = perm.intern(); readPermission(parser, perm); } else if ("assign-permission".equals(name)) { String perm = parser.getAttributeValue(null, "name"); if (perm == null) { Slog.w(TAG, " without name at " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } String uidStr = parser.getAttributeValue(null, "uid"); if (uidStr == null) { Slog.w(TAG, " without uid at " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } int uid = Process.getUidForName(uidStr); if (uid < 0) { Slog.w(TAG, " with unknown uid \"" + uidStr + "\" at " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } perm = perm.intern(); HashSet perms = mSystemPermissions.get(uid); if (perms == null) { perms = new HashSet(); mSystemPermissions.put(uid, perms); } perms.add(perm); XmlUtils.skipCurrentTag(parser); } else if ("library".equals(name)) { String lname = parser.getAttributeValue(null, "name"); String lfile = parser.getAttributeValue(null, "file"); if (lname == null) { Slog.w(TAG, " without name at " + parser.getPositionDescription()); } else if (lfile == null) { Slog.w(TAG, " without file at " + parser.getPositionDescription()); } else { //Log.i(TAG, "Got library " + lname + " in " + lfile); mSharedLibraries.put(lname, new SharedLibraryEntry(lfile, null)); } XmlUtils.skipCurrentTag(parser); continue; } else if ("feature".equals(name)) { String fname = parser.getAttributeValue(null, "name"); if (fname == null) { Slog.w(TAG, " without name at " + parser.getPositionDescription()); } else { //Log.i(TAG, "Got feature " + fname); FeatureInfo fi = new FeatureInfo(); fi.name = fname; mAvailableFeatures.put(fname, fi); } XmlUtils.skipCurrentTag(parser); continue; } else { XmlUtils.skipCurrentTag(parser); continue; } } permReader.close(); } catch (XmlPullParserException e) { Slog.w(TAG, "Got execption parsing permissions.", e); } catch (IOException e) { Slog.w(TAG, "Got execption parsing permissions.", e); } } void readPermission(XmlPullParser parser, String name) throws IOException, XmlPullParserException { name = name.intern(); BasePermission bp = mSettings.mPermissions.get(name); if (bp == null) { bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN); mSettings.mPermissions.put(name, bp); } 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 ("group".equals(tagName)) { String gidStr = parser.getAttributeValue(null, "gid"); if (gidStr != null) { int gid = Process.getGidForName(gidStr); bp.gids = appendInt(bp.gids, gid); } else { Slog.w(TAG, " without gid at " + parser.getPositionDescription()); } } XmlUtils.skipCurrentTag(parser); } } static int[] appendInts(int[] cur, int[] add) { if (add == null) return cur; if (cur == null) return add; final int N = add.length; for (int i=0; i=0; i--) { PackageSetting ps = mSettings.mPackages.get(names[i]); out[i] = ps != null && ps.realName != null ? ps.realName : names[i]; } } return out; } public String[] canonicalToCurrentPackageNames(String[] names) { String[] out = new String[names.length]; // reader synchronized (mPackages) { for (int i=names.length-1; i>=0; i--) { String cur = mSettings.mRenamedPackages.get(names[i]); out[i] = cur != null ? cur : names[i]; } } return out; } @Override public int getPackageUid(String packageName, int userId) { if (!sUserManager.exists(userId)) return -1; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package uid"); // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if(p != null) { return UserHandle.getUid(userId, p.applicationInfo.uid); } PackageSetting ps = mSettings.mPackages.get(packageName); if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) { return -1; } p = ps.pkg; return p != null ? UserHandle.getUid(userId, p.applicationInfo.uid) : -1; } } @Override public int[] getPackageGids(String packageName) { // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getPackageGids" + packageName + ": " + p); if (p != null) { final PackageSetting ps = (PackageSetting)p.mExtras; return ps.getGids(); } } // stupid thing to indicate an error. return new int[0]; } static final PermissionInfo generatePermissionInfo( BasePermission bp, int flags) { if (bp.perm != null) { return PackageParser.generatePermissionInfo(bp.perm, flags); } PermissionInfo pi = new PermissionInfo(); pi.name = bp.name; pi.packageName = bp.sourcePackage; pi.nonLocalizedLabel = bp.name; pi.protectionLevel = bp.protectionLevel; return pi; } public PermissionInfo getPermissionInfo(String name, int flags) { // reader synchronized (mPackages) { final BasePermission p = mSettings.mPermissions.get(name); if (p != null) { return generatePermissionInfo(p, flags); } return null; } } public List queryPermissionsByGroup(String group, int flags) { // reader synchronized (mPackages) { ArrayList out = new ArrayList(10); for (BasePermission p : mSettings.mPermissions.values()) { if (group == null) { if (p.perm == null || p.perm.info.group == null) { out.add(generatePermissionInfo(p, flags)); } } else { if (p.perm != null && group.equals(p.perm.info.group)) { out.add(PackageParser.generatePermissionInfo(p.perm, flags)); } } } if (out.size() > 0) { return out; } return mPermissionGroups.containsKey(group) ? out : null; } } public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) { // reader synchronized (mPackages) { return PackageParser.generatePermissionGroupInfo( mPermissionGroups.get(name), flags); } } public List getAllPermissionGroups(int flags) { // reader synchronized (mPackages) { final int N = mPermissionGroups.size(); ArrayList out = new ArrayList(N); for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) { out.add(PackageParser.generatePermissionGroupInfo(pg, flags)); } return out; } } private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int userId) { if (!sUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { if (ps.pkg == null) { PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags, userId); if (pInfo != null) { return pInfo.applicationInfo; } return null; } return PackageParser.generateApplicationInfo(ps.pkg, flags, ps.readUserState(userId), userId); } return null; } private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags, int userId) { if (!sUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { PackageParser.Package pkg = ps.pkg; if (pkg == null) { if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) { return null; } pkg = new PackageParser.Package(packageName); pkg.applicationInfo.packageName = packageName; pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY; pkg.applicationInfo.publicSourceDir = ps.resourcePathString; pkg.applicationInfo.sourceDir = ps.codePathString; pkg.applicationInfo.dataDir = getDataPathForPackage(packageName, 0).getPath(); pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; } return generatePackageInfo(pkg, flags, userId); } return null; } @Override public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { if (!sUserManager.exists(userId)) return null; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get application info"); // writer synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getApplicationInfo " + packageName + ": " + p); if (p != null) { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) return null; // Note: isEnabledLP() does not apply here - always return info return PackageParser.generateApplicationInfo( p, flags, ps.readUserState(userId), userId); } if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; } if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { return generateApplicationInfoFromSettingsLPw(packageName, flags, userId); } } return null; } public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_CACHE, null); // Queue up an async operation since clearing cache may take a little while. mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); int retCode = -1; synchronized (mInstallLock) { retCode = mInstaller.freeCache(freeStorageSize); if (retCode < 0) { Slog.w(TAG, "Couldn't clear application caches"); } } if (observer != null) { try { observer.onRemoveCompleted(null, (retCode >= 0)); } catch (RemoteException e) { Slog.w(TAG, "RemoveException when invoking call back"); } } } }); } public void freeStorage(final long freeStorageSize, final IntentSender pi) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_CACHE, null); // Queue up an async operation since clearing cache may take a little while. mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); int retCode = -1; synchronized (mInstallLock) { retCode = mInstaller.freeCache(freeStorageSize); if (retCode < 0) { Slog.w(TAG, "Couldn't clear application caches"); } } if(pi != null) { try { // Callback via pending intent int code = (retCode >= 0) ? 1 : 0; pi.sendIntent(null, code, null, null, null); } catch (SendIntentException e1) { Slog.i(TAG, "Failed to send pending intent"); } } } }); } @Override public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get activity info"); synchronized (mPackages) { PackageParser.Activity a = mActivities.mActivities.get(component); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId), userId); } if (mResolveComponentName.equals(component)) { return mResolveActivity; } } return null; } @Override public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get receiver info"); synchronized (mPackages) { PackageParser.Activity a = mReceivers.mActivities.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getReceiverInfo " + component + ": " + a); if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId), userId); } } return null; } @Override public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get service info"); synchronized (mPackages) { PackageParser.Service s = mServices.mServices.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getServiceInfo " + component + ": " + s); if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId), userId); } } return null; } @Override public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get provider info"); synchronized (mPackages) { PackageParser.Provider p = mProviders.mProviders.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getProviderInfo " + component + ": " + p); if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), userId); } } return null; } public String[] getSystemSharedLibraryNames() { Set libSet; synchronized (mPackages) { libSet = mSharedLibraries.keySet(); int size = libSet.size(); if (size > 0) { String[] libs = new String[size]; libSet.toArray(libs); return libs; } } return null; } public FeatureInfo[] getSystemAvailableFeatures() { Collection featSet; synchronized (mPackages) { featSet = mAvailableFeatures.values(); int size = featSet.size(); if (size > 0) { FeatureInfo[] features = new FeatureInfo[size+1]; featSet.toArray(features); FeatureInfo fi = new FeatureInfo(); fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version", FeatureInfo.GL_ES_VERSION_UNDEFINED); features[size] = fi; return features; } } return null; } public boolean hasSystemFeature(String name) { synchronized (mPackages) { return mAvailableFeatures.containsKey(name); } } private void checkValidCaller(int uid, int userId) { if (UserHandle.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return; throw new SecurityException("Caller uid=" + uid + " is not privileged to communicate with user=" + userId); } public int checkPermission(String permName, String pkgName) { synchronized (mPackages) { PackageParser.Package p = mPackages.get(pkgName); if (p != null && p.mExtras != null) { PackageSetting ps = (PackageSetting)p.mExtras; if (ps.sharedUser != null) { if (ps.sharedUser.grantedPermissions.contains(permName)) { return PackageManager.PERMISSION_GRANTED; } } else if (ps.grantedPermissions.contains(permName)) { return PackageManager.PERMISSION_GRANTED; } } } return PackageManager.PERMISSION_DENIED; } public int checkUidPermission(String permName, int uid) { synchronized (mPackages) { Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); if (obj != null) { GrantedPermissions gp = (GrantedPermissions)obj; if (gp.grantedPermissions.contains(permName)) { return PackageManager.PERMISSION_GRANTED; } } else { HashSet perms = mSystemPermissions.get(uid); if (perms != null && perms.contains(permName)) { return PackageManager.PERMISSION_GRANTED; } } } return PackageManager.PERMISSION_DENIED; } /** * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller. * @param message the message to log on security exception * @return */ private void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission, String message) { if (userId < 0) { throw new IllegalArgumentException("Invalid userId " + userId); } if (userId == UserHandle.getUserId(callingUid)) return; if (callingUid != Process.SYSTEM_UID && callingUid != 0) { if (requireFullPermission) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); } else { try { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); } catch (SecurityException se) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, message); } } } } private BasePermission findPermissionTreeLP(String permName) { for(BasePermission bp : mSettings.mPermissionTrees.values()) { if (permName.startsWith(bp.name) && permName.length() > bp.name.length() && permName.charAt(bp.name.length()) == '.') { return bp; } } return null; } private BasePermission checkPermissionTreeLP(String permName) { if (permName != null) { BasePermission bp = findPermissionTreeLP(permName); if (bp != null) { if (bp.uid == UserHandle.getAppId(Binder.getCallingUid())) { return bp; } throw new SecurityException("Calling uid " + Binder.getCallingUid() + " is not allowed to add to permission tree " + bp.name + " owned by uid " + bp.uid); } } throw new SecurityException("No permission tree found for " + permName); } static boolean compareStrings(CharSequence s1, CharSequence s2) { if (s1 == null) { return s2 == null; } if (s2 == null) { return false; } if (s1.getClass() != s2.getClass()) { return false; } return s1.equals(s2); } static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) { if (pi1.icon != pi2.icon) return false; if (pi1.logo != pi2.logo) return false; if (pi1.protectionLevel != pi2.protectionLevel) return false; if (!compareStrings(pi1.name, pi2.name)) return false; if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false; // We'll take care of setting this one. if (!compareStrings(pi1.packageName, pi2.packageName)) return false; // These are not currently stored in settings. //if (!compareStrings(pi1.group, pi2.group)) return false; //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false; //if (pi1.labelRes != pi2.labelRes) return false; //if (pi1.descriptionRes != pi2.descriptionRes) return false; return true; } boolean addPermissionLocked(PermissionInfo info, boolean async) { if (info.labelRes == 0 && info.nonLocalizedLabel == null) { throw new SecurityException("Label must be specified in permission"); } BasePermission tree = checkPermissionTreeLP(info.name); BasePermission bp = mSettings.mPermissions.get(info.name); boolean added = bp == null; boolean changed = true; int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel); if (added) { bp = new BasePermission(info.name, tree.sourcePackage, BasePermission.TYPE_DYNAMIC); } else if (bp.type != BasePermission.TYPE_DYNAMIC) { throw new SecurityException( "Not allowed to modify non-dynamic permission " + info.name); } else { if (bp.protectionLevel == fixedLevel && bp.perm.owner.equals(tree.perm.owner) && bp.uid == tree.uid && comparePermissionInfos(bp.perm.info, info)) { changed = false; } } bp.protectionLevel = fixedLevel; info = new PermissionInfo(info); info.protectionLevel = fixedLevel; bp.perm = new PackageParser.Permission(tree.perm.owner, info); bp.perm.info.packageName = tree.perm.info.packageName; bp.uid = tree.uid; if (added) { mSettings.mPermissions.put(info.name, bp); } if (changed) { if (!async) { mSettings.writeLPr(); } else { scheduleWriteSettingsLocked(); } } return added; } public boolean addPermission(PermissionInfo info) { synchronized (mPackages) { return addPermissionLocked(info, false); } } public boolean addPermissionAsync(PermissionInfo info) { synchronized (mPackages) { return addPermissionLocked(info, true); } } public void removePermission(String name) { synchronized (mPackages) { checkPermissionTreeLP(name); BasePermission bp = mSettings.mPermissions.get(name); if (bp != null) { if (bp.type != BasePermission.TYPE_DYNAMIC) { throw new SecurityException( "Not allowed to modify non-dynamic permission " + name); } mSettings.mPermissions.remove(name); mSettings.writeLPr(); } } } private static void checkGrantRevokePermissions(PackageParser.Package pkg, BasePermission bp) { int index = pkg.requestedPermissions.indexOf(bp.name); if (index == -1) { throw new SecurityException("Package " + pkg.packageName + " has not requested permission " + bp.name); } boolean isNormal = ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_NORMAL); boolean isDangerous = ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_DANGEROUS); boolean isDevelopment = ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0); if (!isNormal && !isDangerous && !isDevelopment) { throw new SecurityException("Permission " + bp.name + " is not a changeable permission type"); } if (isNormal || isDangerous) { if (pkg.requestedPermissionsRequired.get(index)) { throw new SecurityException("Can't change " + bp.name + ". It is required by the application"); } } } public void grantPermission(String packageName, String permissionName) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null); synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } final BasePermission bp = mSettings.mPermissions.get(permissionName); if (bp == null) { throw new IllegalArgumentException("Unknown permission: " + permissionName); } checkGrantRevokePermissions(pkg, bp); final PackageSetting ps = (PackageSetting) pkg.mExtras; if (ps == null) { return; } final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps; if (gp.grantedPermissions.add(permissionName)) { if (ps.haveGids) { gp.gids = appendInts(gp.gids, bp.gids); } mSettings.writeLPr(); } } } public void revokePermission(String packageName, String permissionName) { int changedAppId = -1; synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } if (pkg.applicationInfo.uid != Binder.getCallingUid()) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null); } final BasePermission bp = mSettings.mPermissions.get(permissionName); if (bp == null) { throw new IllegalArgumentException("Unknown permission: " + permissionName); } checkGrantRevokePermissions(pkg, bp); final PackageSetting ps = (PackageSetting) pkg.mExtras; if (ps == null) { return; } final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps; if (gp.grantedPermissions.remove(permissionName)) { gp.grantedPermissions.remove(permissionName); if (ps.haveGids) { gp.gids = removeInts(gp.gids, bp.gids); } mSettings.writeLPr(); changedAppId = ps.appId; } } if (changedAppId >= 0) { // We changed the perm on someone, kill its processes. IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { final int callingUserId = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { //XXX we should only revoke for the calling user's app permissions, // but for now we impact all users. //am.killUid(UserHandle.getUid(callingUserId, changedAppId), // "revoke " + permissionName); int[] users = sUserManager.getUserIds(); for (int user : users) { am.killUid(UserHandle.getUid(user, changedAppId), "revoke " + permissionName); } } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); } } } } public boolean isProtectedBroadcast(String actionName) { synchronized (mPackages) { return mProtectedBroadcasts.contains(actionName); } } public int checkSignatures(String pkg1, String pkg2) { synchronized (mPackages) { final PackageParser.Package p1 = mPackages.get(pkg1); final PackageParser.Package p2 = mPackages.get(pkg2); if (p1 == null || p1.mExtras == null || p2 == null || p2.mExtras == null) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } return compareSignatures(p1.mSignatures, p2.mSignatures); } } public int checkUidSignatures(int uid1, int uid2) { // Map to base uids. uid1 = UserHandle.getAppId(uid1); uid2 = UserHandle.getAppId(uid2); // reader synchronized (mPackages) { Signature[] s1; Signature[] s2; Object obj = mSettings.getUserIdLPr(uid1); if (obj != null) { if (obj instanceof SharedUserSetting) { s1 = ((SharedUserSetting)obj).signatures.mSignatures; } else if (obj instanceof PackageSetting) { s1 = ((PackageSetting)obj).signatures.mSignatures; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } obj = mSettings.getUserIdLPr(uid2); if (obj != null) { if (obj instanceof SharedUserSetting) { s2 = ((SharedUserSetting)obj).signatures.mSignatures; } else if (obj instanceof PackageSetting) { s2 = ((PackageSetting)obj).signatures.mSignatures; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } return compareSignatures(s1, s2); } } /** * Compares two sets of signatures. Returns: *
* {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null, *
* {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null, *
* {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null, *
* {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical, *
* {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ. */ static int compareSignatures(Signature[] s1, Signature[] s2) { if (s1 == null) { return s2 == null ? PackageManager.SIGNATURE_NEITHER_SIGNED : PackageManager.SIGNATURE_FIRST_NOT_SIGNED; } if (s2 == null) { return PackageManager.SIGNATURE_SECOND_NOT_SIGNED; } if (s1.length != s2.length) { return PackageManager.SIGNATURE_NO_MATCH; } // Since both signature sets are of size 1, we can compare without HashSets. if (s1.length == 1) { return s1[0].equals(s2[0]) ? PackageManager.SIGNATURE_MATCH : PackageManager.SIGNATURE_NO_MATCH; } HashSet set1 = new HashSet(); for (Signature sig : s1) { set1.add(sig); } HashSet set2 = new HashSet(); for (Signature sig : s2) { set2.add(sig); } // Make sure s2 contains all signatures in s1. if (set1.equals(set2)) { return PackageManager.SIGNATURE_MATCH; } return PackageManager.SIGNATURE_NO_MATCH; } public String[] getPackagesForUid(int uid) { uid = UserHandle.getAppId(uid); // reader synchronized (mPackages) { Object obj = mSettings.getUserIdLPr(uid); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; final int N = sus.packages.size(); final String[] res = new String[N]; final Iterator it = sus.packages.iterator(); int i = 0; while (it.hasNext()) { res[i++] = it.next().name; } return res; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; return new String[] { ps.name }; } } return null; } public String getNameForUid(int uid) { // reader synchronized (mPackages) { Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; return sus.name + ":" + sus.userId; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; return ps.name; } } return null; } public int getUidForSharedUser(String sharedUserName) { if(sharedUserName == null) { return -1; } // reader synchronized (mPackages) { final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false); if (suid == null) { return -1; } return suid.userId; } } 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) { if (!sUserManager.exists(userId)) return null; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "resolve intent"); List query = queryIntentActivities(intent, resolvedType, flags, userId); return chooseBestActivity(intent, resolvedType, flags, query, userId); } @Override public void setLastChosenActivity(Intent intent, String resolvedType, int flags, IntentFilter filter, int match, ComponentName activity) { final int userId = UserHandle.getCallingUserId(); if (DEBUG_PREFERRED) { Log.v(TAG, "setLastChosenActivity intent=" + intent + " resolvedType=" + resolvedType + " flags=" + flags + " filter=" + filter + " match=" + match + " activity=" + activity); filter.dump(new PrintStreamPrinter(System.out), " "); } intent.setComponent(null); List query = queryIntentActivities(intent, resolvedType, flags, userId); // Find any earlier preferred or last chosen entries and nuke them findPreferredActivity(intent, resolvedType, flags, query, 0, false, true, false, userId); // Add the new activity as the last chosen for this filter addPreferredActivityInternal(filter, match, null, activity, false, userId); } @Override public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) { final int userId = UserHandle.getCallingUserId(); if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent); List query = queryIntentActivities(intent, resolvedType, flags, userId); return findPreferredActivity(intent, resolvedType, flags, query, 0, false, false, false, userId); } private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int flags, List query, int userId) { if (query != null) { final int N = query.size(); if (N == 1) { return query.get(0); } else if (N > 1) { final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); // If there is more than one activity with the same priority, // then let the user decide between them. ResolveInfo r0 = query.get(0); ResolveInfo r1 = query.get(1); if (DEBUG_INTENT_MATCHING || debug) { Slog.v(TAG, r0.activityInfo.name + "=" + r0.priority + " vs " + r1.activityInfo.name + "=" + r1.priority); } // If the first activity has a higher priority, or a different // default, then it is always desireable to pick it. if (r0.priority != r1.priority || r0.preferredOrder != r1.preferredOrder || r0.isDefault != r1.isDefault) { return query.get(0); } // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivity(intent, resolvedType, flags, query, r0.priority, true, false, debug, userId); if (ri != null) { return ri; } if (userId != 0) { ri = new ResolveInfo(mResolveInfo); ri.activityInfo = new ActivityInfo(ri.activityInfo); ri.activityInfo.applicationInfo = new ApplicationInfo( ri.activityInfo.applicationInfo); ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(ri.activityInfo.applicationInfo.uid)); return ri; } return mResolveInfo; } } return null; } ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, List query, int priority, boolean always, boolean removeMatches, boolean debug, int userId) { if (!sUserManager.exists(userId)) return null; // writer synchronized (mPackages) { if (intent.getSelector() != null) { intent = intent.getSelector(); } if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); 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..."); List prefs = pir != null ? pir.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId) : null; if (prefs != null && prefs.size() > 0) { // First figure out how good the original match set is. // We will only allow preferred activities that came // from the same match quality. int match = 0; if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); final int N = query.size(); for (int j=0; j match) { match = ri.match; } } if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match)); match &= IntentFilter.MATCH_CATEGORY_MASK; final int M = prefs.size(); for (int i=0; i") + "\n component=" + pa.mPref.mComponent); pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); } if (pa.mPref.mMatch != match) { if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match " + Integer.toHexString(pa.mPref.mMatch)); continue; } // If it's not an "always" type preferred activity and that's what we're // looking for, skip it. if (always && !pa.mPref.mAlways) { if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); continue; } final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags | PackageManager.GET_DISABLED_COMPONENTS, userId); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Found 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 preferred activity // component is no longer known. Most likely an update // to the app was installed and in the new version this // component no longer exists. Clean it up by removing // it from the preferred activities list, and skip it. Slog.w(TAG, "Removing dangling preferred activity: " + pa.mPref.mComponent); pir.removeFilter(pa); continue; } for (int j=0; j queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return Collections.emptyList(); enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities"); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } if (comp != null) { final List list = new ArrayList(1); final ActivityInfo ai = getActivityInfo(comp, flags, userId); if (ai != null) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; list.add(ri); } return list; } // reader synchronized (mPackages) { final String pkgName = intent.getPackage(); if (pkgName == null) { return mActivities.queryIntent(intent, resolvedType, flags, userId); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { return mActivities.queryIntentForPackage(intent, resolvedType, flags, pkg.activities, userId); } return new ArrayList(); } } @Override public List queryIntentActivityOptions(ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return Collections.emptyList(); enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activity options"); final String resultsAction = intent.getAction(); List results = queryIntentActivities(intent, resolvedType, flags | PackageManager.GET_RESOLVED_FILTER, userId); if (DEBUG_INTENT_MATCHING) { Log.v(TAG, "Query " + intent + ": " + results); } int specificsPos = 0; int N; // todo: note that the algorithm used here is O(N^2). This // isn't a problem in our current environment, but if we start running // into situations where we have more than 5 or 10 matches then this // should probably be changed to something smarter... // First we go through and resolve each of the specific items // that were supplied, taking care of removing any corresponding // duplicate items in the generic resolve list. if (specifics != null) { for (int i=0; i it = rii.filter.actionsIterator(); if (it == null) { continue; } while (it.hasNext()) { final String action = it.next(); if (resultsAction != null && resultsAction.equals(action)) { // If this action was explicitly requested, then don't // remove things that have it. continue; } for (int j=i+1; j queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return Collections.emptyList(); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } if (comp != null) { List list = new ArrayList(1); ActivityInfo ai = getReceiverInfo(comp, flags, userId); if (ai != null) { ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; list.add(ri); } return list; } // reader synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { return mReceivers.queryIntent(intent, resolvedType, flags, userId); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers, userId); } return null; } } @Override public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) { List query = queryIntentServices(intent, resolvedType, flags, userId); if (!sUserManager.exists(userId)) return null; if (query != null) { if (query.size() >= 1) { // If there is more than one service with the same priority, // just arbitrarily pick the first one. return query.get(0); } } return null; } @Override public List queryIntentServices(Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return Collections.emptyList(); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } if (comp != null) { final List list = new ArrayList(1); final ServiceInfo si = getServiceInfo(comp, flags, userId); if (si != null) { final ResolveInfo ri = new ResolveInfo(); ri.serviceInfo = si; list.add(ri); } return list; } // reader synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { return mServices.queryIntent(intent, resolvedType, flags, userId); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services, userId); } return null; } } @Override public List queryIntentContentProviders( Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return Collections.emptyList(); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } if (comp != null) { final List list = new ArrayList(1); final ProviderInfo pi = getProviderInfo(comp, flags, userId); if (pi != null) { final ResolveInfo ri = new ResolveInfo(); ri.providerInfo = pi; list.add(ri); } return list; } // reader synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { return mProviders.queryIntent(intent, resolvedType, flags, userId); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { return mProviders.queryIntentForPackage( intent, resolvedType, flags, pkg.providers, userId); } return null; } } @Override public ParceledListSlice getInstalledPackages(int flags, int userId) { final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "get installed packages"); // writer synchronized (mPackages) { ArrayList list; if (listUninstalled) { list = new ArrayList(mSettings.mPackages.size()); for (PackageSetting ps : mSettings.mPackages.values()) { PackageInfo pi; if (ps.pkg != null) { pi = generatePackageInfo(ps.pkg, flags, userId); } else { pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId); } if (pi != null) { list.add(pi); } } } else { list = new ArrayList(mPackages.size()); for (PackageParser.Package p : mPackages.values()) { PackageInfo pi = generatePackageInfo(p, flags, userId); if (pi != null) { list.add(pi); } } } return new ParceledListSlice(list); } } private void addPackageHoldingPermissions(ArrayList list, PackageSetting ps, String[] permissions, boolean[] tmp, int flags, int userId) { int numMatch = 0; final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; for (int i=0; i getPackagesHoldingPermissions( String[] permissions, int flags, int userId) { if (!sUserManager.exists(userId)) return null; final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; // writer synchronized (mPackages) { ArrayList list = new ArrayList(); boolean[] tmpBools = new boolean[permissions.length]; if (listUninstalled) { for (PackageSetting ps : mSettings.mPackages.values()) { addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId); } } else { for (PackageParser.Package pkg : mPackages.values()) { PackageSetting ps = (PackageSetting)pkg.mExtras; if (ps != null) { addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId); } } } return new ParceledListSlice(list); } } @Override public ParceledListSlice getInstalledApplications(int flags, int userId) { if (!sUserManager.exists(userId)) return null; final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; // writer synchronized (mPackages) { ArrayList list; if (listUninstalled) { list = new ArrayList(mSettings.mPackages.size()); for (PackageSetting ps : mSettings.mPackages.values()) { ApplicationInfo ai; if (ps.pkg != null) { ai = PackageParser.generateApplicationInfo(ps.pkg, flags, ps.readUserState(userId), userId); } else { ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId); } if (ai != null) { list.add(ai); } } } else { list = new ArrayList(mPackages.size()); for (PackageParser.Package p : mPackages.values()) { if (p.mExtras != null) { ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, ((PackageSetting)p.mExtras).readUserState(userId), userId); if (ai != null) { list.add(ai); } } } } return new ParceledListSlice(list); } } public List getPersistentApplications(int flags) { final ArrayList finalList = new ArrayList(); // reader synchronized (mPackages) { final Iterator i = mPackages.values().iterator(); final int userId = UserHandle.getCallingUserId(); while (i.hasNext()) { final PackageParser.Package p = i.next(); if (p.applicationInfo != null && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 && (!mSafeMode || isSystemApp(p))) { PackageSetting ps = mSettings.mPackages.get(p.packageName); if (ps != null) { ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { finalList.add(ai); } } } } } return finalList; } @Override public ProviderInfo resolveContentProvider(String name, int flags, int userId) { if (!sUserManager.exists(userId)) return null; // reader synchronized (mPackages) { final PackageParser.Provider provider = mProvidersByAuthority.get(name); PackageSetting ps = provider != null ? mSettings.mPackages.get(provider.owner.packageName) : null; return ps != null && mSettings.isEnabledLPr(provider.info, flags, userId) && (!mSafeMode || (provider.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0) ? PackageParser.generateProviderInfo(provider, flags, ps.readUserState(userId), userId) : null; } } /** * @deprecated */ @Deprecated public void querySyncProviders(List outNames, List outInfo) { // reader synchronized (mPackages) { final Iterator> i = mProvidersByAuthority .entrySet().iterator(); final int userId = UserHandle.getCallingUserId(); while (i.hasNext()) { Map.Entry entry = i.next(); PackageParser.Provider p = entry.getValue(); PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); if (ps != null && p.syncable && (!mSafeMode || (p.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0)) { ProviderInfo info = PackageParser.generateProviderInfo(p, 0, ps.readUserState(userId), userId); if (info != null) { outNames.add(entry.getKey()); outInfo.add(info); } } } } } public List queryContentProviders(String processName, int uid, int flags) { ArrayList finalList = null; // reader synchronized (mPackages) { final Iterator i = mProviders.mProviders.values().iterator(); final int userId = processName != null ? UserHandle.getUserId(uid) : UserHandle.getCallingUserId(); while (i.hasNext()) { final PackageParser.Provider p = i.next(); PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); if (ps != null && p.info.authority != null && (processName == null || (p.info.processName.equals(processName) && UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) && mSettings.isEnabledLPr(p.info, flags, userId) && (!mSafeMode || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) { if (finalList == null) { finalList = new ArrayList(3); } ProviderInfo info = PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), userId); if (info != null) { finalList.add(info); } } } } if (finalList != null) { Collections.sort(finalList, mProviderInitOrderSorter); } return finalList; } public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) { // reader synchronized (mPackages) { final PackageParser.Instrumentation i = mInstrumentation.get(name); return PackageParser.generateInstrumentationInfo(i, flags); } } public List queryInstrumentation(String targetPackage, int flags) { ArrayList finalList = new ArrayList(); // reader synchronized (mPackages) { final Iterator i = mInstrumentation.values().iterator(); while (i.hasNext()) { final PackageParser.Instrumentation p = i.next(); if (targetPackage == null || targetPackage.equals(p.info.targetPackage)) { InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p, flags); if (ii != null) { finalList.add(ii); } } } } return finalList; } private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { String[] files = dir.list(); if (files == null) { Log.d(TAG, "No files in app dir " + dir); return; } if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Scanning app dir " + dir + " scanMode=" + scanMode + " flags=0x" + Integer.toHexString(flags)); } int i; for (i=0; i