blob: e9a9f46c0cf92451854d53dbb8c63a7bbb479c1d [file] [log] [blame]
/*
* 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.DeviceStorageMonitorService;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
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.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 android.view.WindowManager;
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;
/**
* 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 REMOVE_CHATTY = 1<<16;
/**
* 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 HandlerThread mHandlerThread = new HandlerThread("PackageManager",
Process.THREAD_PRIORITY_BACKGROUND);
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<String, PackageParser.Package> mAppDirs =
new HashMap<String, PackageParser.Package>();
// Information for the parser to write more useful error messages.
File mScanningPath;
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<String, PackageParser.Package> mPackages =
new HashMap<String, PackageParser.Package>();
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<HashSet<String>> mSystemPermissions =
new SparseArray<HashSet<String>>();
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<String, SharedLibraryEntry> mSharedLibraries
= new HashMap<String, SharedLibraryEntry>();
// 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<String, FeatureInfo> mAvailableFeatures =
new HashMap<String, FeatureInfo>();
// 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<String, PackageParser.Provider> mProvidersByAuthority =
new HashMap<String, PackageParser.Provider>();
// Mapping from instrumentation class names to info about them.
final HashMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
new HashMap<ComponentName, PackageParser.Instrumentation>();
// Mapping from permission names to info about them.
final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups =
new HashMap<String, PackageParser.PermissionGroup>();
// Packages whose data we have transfered into another package, thus
// should no longer exist.
final HashSet<String> mTransferedPackages = new HashSet<String>();
// Broadcast actions that are only available to the system.
final HashSet<String> mProtectedBroadcasts = new HashSet<String>();
/** List of packages waiting for verification. */
final SparseArray<PackageVerificationState> mPendingVerification
= new SparseArray<PackageVerificationState>();
HashSet<PackageParser.Package> 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 <package name -> components within that package>
final SparseArray<HashMap<String, ArrayList<String>>> mUidMap;
public PendingPackageBroadcasts() {
mUidMap = new SparseArray<HashMap<String, ArrayList<String>>>(2);
}
public ArrayList<String> get(int userId, String packageName) {
HashMap<String, ArrayList<String>> packages = getOrAllocate(userId);
return packages.get(packageName);
}
public void put(int userId, String packageName, ArrayList<String> components) {
HashMap<String, ArrayList<String>> packages = getOrAllocate(userId);
packages.put(packageName, components);
}
public void remove(int userId, String packageName) {
HashMap<String, ArrayList<String>> 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<String, ArrayList<String>> 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<String, ArrayList<String>> getOrAllocate(int userId) {
HashMap<String, ArrayList<String>> map = mUidMap.get(userId);
if (map == null) {
map = new HashMap<String, ArrayList<String>>();
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<Integer> mDirtyUsers = new HashSet<Integer>();
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<PostInstallData> mRunningInstalls = new SparseArray<PostInstallData>();
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<HandlerParams> mPendingInstalls =
new ArrayList<HandlerParams>();
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<String> 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<Map.Entry<String, ArrayList<String>>> it
= mPendingBroadcasts.packagesForUserId(packageUserId)
.entrySet().iterator();
while (it.hasNext() && i < size) {
Map.Entry<String, ArrayList<String>> 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<res.newUsers.length; i++) {
int user = res.newUsers[i];
boolean isNew = true;
for (int j=0; j<res.origUsers.length; j++) {
if (res.origUsers[j] == user) {
isNew = false;
break;
}
}
if (isNew) {
int[] newFirst = new int[firstUsers.length+1];
System.arraycopy(firstUsers, 0, newFirst, 0,
firstUsers.length);
newFirst[firstUsers.length] = user;
firstUsers = newFirst;
} else {
int[] newUpdate = new int[updateUsers.length+1];
System.arraycopy(updateUsers, 0, newUpdate, 0,
updateUsers.length);
newUpdate[updateUsers.length] = user;
updateUsers = newUpdate;
}
}
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,
extras, null, null, firstUsers);
final boolean update = res.removedInfo.removedPackage != null;
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,
extras, null, null, updateUsers);
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
res.pkg.applicationInfo.packageName,
extras, null, null, updateUsers);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null, null,
res.pkg.applicationInfo.packageName, null, updateUsers);
// treat asec-hosted packages like removable media on upgrade
if (isForwardLocked(res.pkg) || isExternal(res.pkg)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg
+ " is ASEC-hosted -> AVAILABLE");
}
int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
ArrayList<String> pkgList = new ArrayList<String>(1);
pkgList.add(res.pkg.applicationInfo.packageName);
sendResourcesChangedBroadcast(true, false,
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<AsecInstallArgs> args = (Set<AsecInstallArgs>) 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;
}
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;
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
d.getMetrics(mMetrics);
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName());
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<String> alreadyDexOpted = new HashSet<String>();
/**
* 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<paths.length; i++) {
alreadyDexOpted.add(paths[i]);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
boolean didDexOpt = false;
/**
* Ensure all external libraries have had dexopt run on them.
*/
if (mSharedLibraries.size() > 0) {
Iterator<SharedLibraryEntry> 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<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
String path = libPath.getPath();
// Skip the file if we alrady did it.
if (alreadyDexOpted.contains(path)) {
continue;
}
// Skip the file if it is not a type we want to dexopt.
if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
continue;
}
try {
if (dalvik.system.DexFile.isDexOptNeeded(path)) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true);
didDexOpt = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
} catch (IOException e) {
Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
}
if (didDexOpt) {
File dalvikCacheDir = new File(dataDir, "dalvik-cache");
// If we had to do a dexopt of one of the previous
// things, then something on the system has changed.
// Consider this significant, and wipe away all other
// existing dexopt files to ensure we don't leave any
// dangling around.
String[] files = dalvikCacheDir.list();
if (files != null) {
for (int i=0; i<files.length; i++) {
String fn = files[i];
if (fn.startsWith("data@app@")
|| fn.startsWith("data@app-private@")) {
Slog.i(TAG, "Pruning dalvik file: " + fn);
(new File(dalvikCacheDir, fn)).delete();
}
}
}
}
// Find base frameworks (resource packages without code).
mFrameworkInstallObserver = new AppDirObserver(
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
mFrameworkInstallObserver.startWatching();
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanMode | SCAN_NO_DEX, 0);
// Collected privileged system packages.
File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
mPrivilegedInstallObserver = new AppDirObserver(
privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true);
mPrivilegedInstallObserver.startWatching();
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);
// Collect ordinary system packages.
File systemAppDir = new File(Environment.getRootDirectory(), "app");
mSystemInstallObserver = new AppDirObserver(
systemAppDir.getPath(), OBSERVER_EVENTS, true, false);
mSystemInstallObserver.startWatching();
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
// Collect all vendor packages.
File vendorAppDir = new File("/vendor/app");
mVendorInstallObserver = new AppDirObserver(
vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
mVendorInstallObserver.startWatching();
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
mInstaller.moveFiles();
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if (!mOnlyCore) {
Iterator<PackageSetting> 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<PackageSetting> 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<ResolveInfo> 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, "<group> 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, "<permission> 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, "<assign-permission> without name at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
String uidStr = parser.getAttributeValue(null, "uid");
if (uidStr == null) {
Slog.w(TAG, "<assign-permission> without uid at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
int uid = Process.getUidForName(uidStr);
if (uid < 0) {
Slog.w(TAG, "<assign-permission> with unknown uid \""
+ uidStr + "\" at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
HashSet<String> perms = mSystemPermissions.get(uid);
if (perms == null) {
perms = new HashSet<String>();
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, "<library> without name at "
+ parser.getPositionDescription());
} else if (lfile == null) {
Slog.w(TAG, "<library> 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, "<feature> 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, "<group> 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<N; i++) {
cur = appendInt(cur, add[i]);
}
return cur;
}
static int[] removeInts(int[] cur, int[] rem) {
if (rem == null) return cur;
if (cur == null) return cur;
final int N = rem.length;
for (int i=0; i<N; i++) {
cur = removeInt(cur, rem[i]);
}
return cur;
}
PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
PackageInfo pi;
final PackageSetting ps = (PackageSetting) p.mExtras;
if (ps == null) {
return null;
}
final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
final PackageUserState state = ps.readUserState(userId);
return PackageParser.generatePackageInfo(p, gp.gids, flags,
ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions,
state, userId);
}
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package info");
// reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if (DEBUG_PACKAGE_INFO)
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
return generatePackageInfo(p, flags, userId);
}
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
}
}
return null;
}
public String[] currentToCanonicalPackageNames(String[] names) {
String[] out = new String[names.length];
// reader
synchronized (mPackages) {
for (int i=names.length-1; 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<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
// reader
synchronized (mPackages) {
ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(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<PermissionGroupInfo> getAllPermissionGroups(int flags) {
// reader
synchronized (mPackages) {
final int N = mPermissionGroups.size();
ArrayList<PermissionGroupInfo> out
= new ArrayList<PermissionGroupInfo>(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<String> 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<FeatureInfo> 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<String> 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) {