diff options
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/app/ActivityThread.java | 1535 | ||||
-rw-r--r-- | core/java/android/app/AppGlobals.java | 49 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 14 | ||||
-rw-r--r-- | core/java/android/app/LoadedApk.java | 1103 | ||||
-rw-r--r-- | core/java/android/content/ContentResolver.java | 5 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteDatabase.java | 3 |
6 files changed, 1405 insertions, 1304 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 0ce790e..6599096 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -25,7 +25,6 @@ import android.content.Context; import android.content.IContentProvider; import android.content.Intent; import android.content.IIntentReceiver; -import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; @@ -74,7 +73,6 @@ import android.view.WindowManagerImpl; import com.android.internal.os.BinderInternal; import com.android.internal.os.RuntimeInit; import com.android.internal.os.SamplingProfilerIntegration; -import com.android.internal.util.ArrayUtils; import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; @@ -82,12 +80,9 @@ import java.io.File; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.PrintWriter; import java.lang.ref.WeakReference; -import java.net.URL; import java.util.ArrayList; -import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -98,18 +93,6 @@ import java.util.regex.Pattern; import dalvik.system.SamplingProfiler; -final class IntentReceiverLeaked extends AndroidRuntimeException { - public IntentReceiverLeaked(String msg) { - super(msg); - } -} - -final class ServiceConnectionLeaked extends AndroidRuntimeException { - public ServiceConnectionLeaked(String msg) { - super(msg); - } -} - final class SuperNotCalledException extends AndroidRuntimeException { public SuperNotCalledException(String msg) { super(msg); @@ -125,10 +108,10 @@ final class SuperNotCalledException extends AndroidRuntimeException { * {@hide} */ public final class ActivityThread { - private static final String TAG = "ActivityThread"; + static final String TAG = "ActivityThread"; private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; - private static final boolean DEBUG_BROADCAST = false; + static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + static final boolean DEBUG_BROADCAST = false; private static final boolean DEBUG_RESULTS = false; private static final boolean DEBUG_BACKUP = false; private static final boolean DEBUG_CONFIGURATION = false; @@ -138,1162 +121,65 @@ public final class ActivityThread { private static final int LOG_ON_PAUSE_CALLED = 30021; private static final int LOG_ON_RESUME_CALLED = 30022; + static ContextImpl mSystemContext = null; - public static final ActivityThread currentActivityThread() { - return (ActivityThread)sThreadLocal.get(); - } - - public static final String currentPackageName() - { - ActivityThread am = currentActivityThread(); - return (am != null && am.mBoundApplication != null) - ? am.mBoundApplication.processName : null; - } - - public static IPackageManager getPackageManager() { - if (sPackageManager != null) { - //Slog.v("PackageManager", "returning cur default = " + sPackageManager); - return sPackageManager; - } - IBinder b = ServiceManager.getService("package"); - //Slog.v("PackageManager", "default service binder = " + b); - sPackageManager = IPackageManager.Stub.asInterface(b); - //Slog.v("PackageManager", "default service = " + sPackageManager); - return sPackageManager; - } - - DisplayMetrics getDisplayMetricsLocked(boolean forceUpdate) { - if (mDisplayMetrics != null && !forceUpdate) { - return mDisplayMetrics; - } - if (mDisplay == null) { - WindowManager wm = WindowManagerImpl.getDefault(); - mDisplay = wm.getDefaultDisplay(); - } - DisplayMetrics metrics = mDisplayMetrics = new DisplayMetrics(); - mDisplay.getMetrics(metrics); - //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h=" - // + metrics.heightPixels + " den=" + metrics.density - // + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi); - return metrics; - } - - /** - * Creates the top level Resources for applications with the given compatibility info. - * - * @param resDir the resource directory. - * @param compInfo the compability info. It will use the default compatibility info when it's - * null. - */ - Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) { - ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale); - Resources r; - synchronized (mPackages) { - // Resources is app scale dependent. - if (false) { - Slog.w(TAG, "getTopLevelResources: " + resDir + " / " - + compInfo.applicationScale); - } - WeakReference<Resources> wr = mActiveResources.get(key); - r = wr != null ? wr.get() : null; - //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate()); - if (r != null && r.getAssets().isUpToDate()) { - if (false) { - Slog.w(TAG, "Returning cached resources " + r + " " + resDir - + ": appScale=" + r.getCompatibilityInfo().applicationScale); - } - return r; - } - } - - //if (r != null) { - // Slog.w(TAG, "Throwing away out-of-date resources!!!! " - // + r + " " + resDir); - //} - - AssetManager assets = new AssetManager(); - if (assets.addAssetPath(resDir) == 0) { - return null; - } - - //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); - DisplayMetrics metrics = getDisplayMetricsLocked(false); - r = new Resources(assets, metrics, getConfiguration(), compInfo); - if (false) { - Slog.i(TAG, "Created app resources " + resDir + " " + r + ": " - + r.getConfiguration() + " appScale=" - + r.getCompatibilityInfo().applicationScale); - } - - synchronized (mPackages) { - WeakReference<Resources> wr = mActiveResources.get(key); - Resources existing = wr != null ? wr.get() : null; - if (existing != null && existing.getAssets().isUpToDate()) { - // Someone else already created the resources while we were - // unlocked; go ahead and use theirs. - r.getAssets().close(); - return existing; - } - - // XXX need to remove entries when weak references go away - mActiveResources.put(key, new WeakReference<Resources>(r)); - return r; - } - } - - /** - * Creates the top level resources for the given package. - */ - Resources getTopLevelResources(String resDir, PackageInfo pkgInfo) { - return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo); - } - - final Handler getHandler() { - return mH; - } - - public final static class PackageInfo { - - private final ActivityThread mActivityThread; - private final ApplicationInfo mApplicationInfo; - private final String mPackageName; - private final String mAppDir; - private final String mResDir; - private final String[] mSharedLibraries; - private final String mDataDir; - private final File mDataDirFile; - private final ClassLoader mBaseClassLoader; - private final boolean mSecurityViolation; - private final boolean mIncludeCode; - private Resources mResources; - private ClassLoader mClassLoader; - private Application mApplication; - private CompatibilityInfo mCompatibilityInfo; - - private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers - = new HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>>(); - private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mUnregisteredReceivers - = new HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>>(); - private final HashMap<Context, HashMap<ServiceConnection, ServiceDispatcher>> mServices - = new HashMap<Context, HashMap<ServiceConnection, ServiceDispatcher>>(); - private final HashMap<Context, HashMap<ServiceConnection, ServiceDispatcher>> mUnboundServices - = new HashMap<Context, HashMap<ServiceConnection, ServiceDispatcher>>(); - - int mClientCount = 0; - - Application getApplication() { - return mApplication; - } - - public PackageInfo(ActivityThread activityThread, ApplicationInfo aInfo, - ActivityThread mainThread, ClassLoader baseLoader, - boolean securityViolation, boolean includeCode) { - mActivityThread = activityThread; - mApplicationInfo = aInfo; - mPackageName = aInfo.packageName; - mAppDir = aInfo.sourceDir; - mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir - : aInfo.publicSourceDir; - mSharedLibraries = aInfo.sharedLibraryFiles; - mDataDir = aInfo.dataDir; - mDataDirFile = mDataDir != null ? new File(mDataDir) : null; - mBaseClassLoader = baseLoader; - mSecurityViolation = securityViolation; - mIncludeCode = includeCode; - mCompatibilityInfo = new CompatibilityInfo(aInfo); - - if (mAppDir == null) { - if (mSystemContext == null) { - mSystemContext = - ContextImpl.createSystemContext(mainThread); - mSystemContext.getResources().updateConfiguration( - mainThread.getConfiguration(), - mainThread.getDisplayMetricsLocked(false)); - //Slog.i(TAG, "Created system resources " - // + mSystemContext.getResources() + ": " - // + mSystemContext.getResources().getConfiguration()); - } - mClassLoader = mSystemContext.getClassLoader(); - mResources = mSystemContext.getResources(); - } - } - - public PackageInfo(ActivityThread activityThread, String name, - Context systemContext, ApplicationInfo info) { - mActivityThread = activityThread; - mApplicationInfo = info != null ? info : new ApplicationInfo(); - mApplicationInfo.packageName = name; - mPackageName = name; - mAppDir = null; - mResDir = null; - mSharedLibraries = null; - mDataDir = null; - mDataDirFile = null; - mBaseClassLoader = null; - mSecurityViolation = false; - mIncludeCode = true; - mClassLoader = systemContext.getClassLoader(); - mResources = systemContext.getResources(); - mCompatibilityInfo = new CompatibilityInfo(mApplicationInfo); - } - - public String getPackageName() { - return mPackageName; - } - - public ApplicationInfo getApplicationInfo() { - return mApplicationInfo; - } - - public boolean isSecurityViolation() { - return mSecurityViolation; - } - - /** - * Gets the array of shared libraries that are listed as - * used by the given package. - * - * @param packageName the name of the package (note: not its - * file name) - * @return null-ok; the array of shared libraries, each one - * a fully-qualified path - */ - private static String[] getLibrariesFor(String packageName) { - ApplicationInfo ai = null; - try { - ai = getPackageManager().getApplicationInfo(packageName, - PackageManager.GET_SHARED_LIBRARY_FILES); - } catch (RemoteException e) { - throw new AssertionError(e); - } - - if (ai == null) { - return null; - } - - return ai.sharedLibraryFiles; - } - - /** - * Combines two arrays (of library names) such that they are - * concatenated in order but are devoid of duplicates. The - * result is a single string with the names of the libraries - * separated by colons, or <code>null</code> if both lists - * were <code>null</code> or empty. - * - * @param list1 null-ok; the first list - * @param list2 null-ok; the second list - * @return null-ok; the combination - */ - private static String combineLibs(String[] list1, String[] list2) { - StringBuilder result = new StringBuilder(300); - boolean first = true; - - if (list1 != null) { - for (String s : list1) { - if (first) { - first = false; - } else { - result.append(':'); - } - result.append(s); - } - } - - // Only need to check for duplicates if list1 was non-empty. - boolean dupCheck = !first; - - if (list2 != null) { - for (String s : list2) { - if (dupCheck && ArrayUtils.contains(list1, s)) { - continue; - } - - if (first) { - first = false; - } else { - result.append(':'); - } - result.append(s); - } - } - - return result.toString(); - } - - public ClassLoader getClassLoader() { - synchronized (this) { - if (mClassLoader != null) { - return mClassLoader; - } - - if (mIncludeCode && !mPackageName.equals("android")) { - String zip = mAppDir; - - /* - * The following is a bit of a hack to inject - * instrumentation into the system: If the app - * being started matches one of the instrumentation names, - * then we combine both the "instrumentation" and - * "instrumented" app into the path, along with the - * concatenation of both apps' shared library lists. - */ - - String instrumentationAppDir = - mActivityThread.mInstrumentationAppDir; - String instrumentationAppPackage = - mActivityThread.mInstrumentationAppPackage; - String instrumentedAppDir = - mActivityThread.mInstrumentedAppDir; - String[] instrumentationLibs = null; - - if (mAppDir.equals(instrumentationAppDir) - || mAppDir.equals(instrumentedAppDir)) { - zip = instrumentationAppDir + ":" + instrumentedAppDir; - if (! instrumentedAppDir.equals(instrumentationAppDir)) { - instrumentationLibs = - getLibrariesFor(instrumentationAppPackage); - } - } - - if ((mSharedLibraries != null) || - (instrumentationLibs != null)) { - zip = - combineLibs(mSharedLibraries, instrumentationLibs) - + ':' + zip; - } - - /* - * With all the combination done (if necessary, actually - * create the class loader. - */ - - if (localLOGV) Slog.v(TAG, "Class path: " + zip); - - mClassLoader = - ApplicationLoaders.getDefault().getClassLoader( - zip, mDataDir, mBaseClassLoader); - initializeJavaContextClassLoader(); - } else { - if (mBaseClassLoader == null) { - mClassLoader = ClassLoader.getSystemClassLoader(); - } else { - mClassLoader = mBaseClassLoader; - } - } - return mClassLoader; - } - } - - /** - * Setup value for Thread.getContextClassLoader(). If the - * package will not run in in a VM with other packages, we set - * the Java context ClassLoader to the - * PackageInfo.getClassLoader value. However, if this VM can - * contain multiple packages, we intead set the Java context - * ClassLoader to a proxy that will warn about the use of Java - * context ClassLoaders and then fall through to use the - * system ClassLoader. - * - * <p> Note that this is similar to but not the same as the - * android.content.Context.getClassLoader(). While both - * context class loaders are typically set to the - * PathClassLoader used to load the package archive in the - * single application per VM case, a single Android process - * may contain several Contexts executing on one thread with - * their own logical ClassLoaders while the Java context - * ClassLoader is a thread local. This is why in the case when - * we have multiple packages per VM we do not set the Java - * context ClassLoader to an arbitrary but instead warn the - * user to set their own if we detect that they are using a - * Java library that expects it to be set. - */ - private void initializeJavaContextClassLoader() { - IPackageManager pm = getPackageManager(); - android.content.pm.PackageInfo pi; - try { - pi = pm.getPackageInfo(mPackageName, 0); - } catch (RemoteException e) { - throw new AssertionError(e); - } - /* - * Two possible indications that this package could be - * sharing its virtual machine with other packages: - * - * 1.) the sharedUserId attribute is set in the manifest, - * indicating a request to share a VM with other - * packages with the same sharedUserId. - * - * 2.) the application element of the manifest has an - * attribute specifying a non-default process name, - * indicating the desire to run in another packages VM. - */ - boolean sharedUserIdSet = (pi.sharedUserId != null); - boolean processNameNotDefault = - (pi.applicationInfo != null && - !mPackageName.equals(pi.applicationInfo.processName)); - boolean sharable = (sharedUserIdSet || processNameNotDefault); - ClassLoader contextClassLoader = - (sharable) - ? new WarningContextClassLoader() - : mClassLoader; - Thread.currentThread().setContextClassLoader(contextClassLoader); - } - - private static class WarningContextClassLoader extends ClassLoader { - - private static boolean warned = false; - - private void warn(String methodName) { - if (warned) { - return; - } - warned = true; - Thread.currentThread().setContextClassLoader(getParent()); - Slog.w(TAG, "ClassLoader." + methodName + ": " + - "The class loader returned by " + - "Thread.getContextClassLoader() may fail for processes " + - "that host multiple applications. You should explicitly " + - "specify a context class loader. For example: " + - "Thread.setContextClassLoader(getClass().getClassLoader());"); - } - - @Override public URL getResource(String resName) { - warn("getResource"); - return getParent().getResource(resName); - } - - @Override public Enumeration<URL> getResources(String resName) throws IOException { - warn("getResources"); - return getParent().getResources(resName); - } - - @Override public InputStream getResourceAsStream(String resName) { - warn("getResourceAsStream"); - return getParent().getResourceAsStream(resName); - } - - @Override public Class<?> loadClass(String className) throws ClassNotFoundException { - warn("loadClass"); - return getParent().loadClass(className); - } - - @Override public void setClassAssertionStatus(String cname, boolean enable) { - warn("setClassAssertionStatus"); - getParent().setClassAssertionStatus(cname, enable); - } - - @Override public void setPackageAssertionStatus(String pname, boolean enable) { - warn("setPackageAssertionStatus"); - getParent().setPackageAssertionStatus(pname, enable); - } - - @Override public void setDefaultAssertionStatus(boolean enable) { - warn("setDefaultAssertionStatus"); - getParent().setDefaultAssertionStatus(enable); - } - - @Override public void clearAssertionStatus() { - warn("clearAssertionStatus"); - getParent().clearAssertionStatus(); - } - } - - public String getAppDir() { - return mAppDir; - } - - public String getResDir() { - return mResDir; - } - - public String getDataDir() { - return mDataDir; - } - - public File getDataDirFile() { - return mDataDirFile; - } - - public AssetManager getAssets(ActivityThread mainThread) { - return getResources(mainThread).getAssets(); - } - - public Resources getResources(ActivityThread mainThread) { - if (mResources == null) { - mResources = mainThread.getTopLevelResources(mResDir, this); - } - return mResources; - } - - public Application makeApplication(boolean forceDefaultAppClass, - Instrumentation instrumentation) { - if (mApplication != null) { - return mApplication; - } - - Application app = null; - - String appClass = mApplicationInfo.className; - if (forceDefaultAppClass || (appClass == null)) { - appClass = "android.app.Application"; - } - - try { - java.lang.ClassLoader cl = getClassLoader(); - ContextImpl appContext = new ContextImpl(); - appContext.init(this, null, mActivityThread); - app = mActivityThread.mInstrumentation.newApplication( - cl, appClass, appContext); - appContext.setOuterContext(app); - } catch (Exception e) { - if (!mActivityThread.mInstrumentation.onException(app, e)) { - throw new RuntimeException( - "Unable to instantiate application " + appClass - + ": " + e.toString(), e); - } - } - mActivityThread.mAllApplications.add(app); - mApplication = app; - - if (instrumentation != null) { - try { - instrumentation.callApplicationOnCreate(app); - } catch (Exception e) { - if (!instrumentation.onException(app, e)) { - throw new RuntimeException( - "Unable to create application " + app.getClass().getName() - + ": " + e.toString(), e); - } - } - } - - return app; - } - - public void removeContextRegistrations(Context context, - String who, String what) { - HashMap<BroadcastReceiver, ReceiverDispatcher> rmap = - mReceivers.remove(context); - if (rmap != null) { - Iterator<ReceiverDispatcher> it = rmap.values().iterator(); - while (it.hasNext()) { - ReceiverDispatcher rd = it.next(); - IntentReceiverLeaked leak = new IntentReceiverLeaked( - what + " " + who + " has leaked IntentReceiver " - + rd.getIntentReceiver() + " that was " + - "originally registered here. Are you missing a " + - "call to unregisterReceiver()?"); - leak.setStackTrace(rd.getLocation().getStackTrace()); - Slog.e(TAG, leak.getMessage(), leak); - try { - ActivityManagerNative.getDefault().unregisterReceiver( - rd.getIIntentReceiver()); - } catch (RemoteException e) { - // system crashed, nothing we can do - } - } - } - mUnregisteredReceivers.remove(context); - //Slog.i(TAG, "Receiver registrations: " + mReceivers); - HashMap<ServiceConnection, ServiceDispatcher> smap = - mServices.remove(context); - if (smap != null) { - Iterator<ServiceDispatcher> it = smap.values().iterator(); - while (it.hasNext()) { - ServiceDispatcher sd = it.next(); - ServiceConnectionLeaked leak = new ServiceConnectionLeaked( - what + " " + who + " has leaked ServiceConnection " - + sd.getServiceConnection() + " that was originally bound here"); - leak.setStackTrace(sd.getLocation().getStackTrace()); - Slog.e(TAG, leak.getMessage(), leak); - try { - ActivityManagerNative.getDefault().unbindService( - sd.getIServiceConnection()); - } catch (RemoteException e) { - // system crashed, nothing we can do - } - sd.doForget(); - } - } - mUnboundServices.remove(context); - //Slog.i(TAG, "Service registrations: " + mServices); - } - - public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, - Context context, Handler handler, - Instrumentation instrumentation, boolean registered) { - synchronized (mReceivers) { - ReceiverDispatcher rd = null; - HashMap<BroadcastReceiver, ReceiverDispatcher> map = null; - if (registered) { - map = mReceivers.get(context); - if (map != null) { - rd = map.get(r); - } - } - if (rd == null) { - rd = new ReceiverDispatcher(r, context, handler, - instrumentation, registered); - if (registered) { - if (map == null) { - map = new HashMap<BroadcastReceiver, ReceiverDispatcher>(); - mReceivers.put(context, map); - } - map.put(r, rd); - } - } else { - rd.validate(context, handler); - } - return rd.getIIntentReceiver(); - } - } - - public IIntentReceiver forgetReceiverDispatcher(Context context, - BroadcastReceiver r) { - synchronized (mReceivers) { - HashMap<BroadcastReceiver, ReceiverDispatcher> map = mReceivers.get(context); - ReceiverDispatcher rd = null; - if (map != null) { - rd = map.get(r); - if (rd != null) { - map.remove(r); - if (map.size() == 0) { - mReceivers.remove(context); - } - if (r.getDebugUnregister()) { - HashMap<BroadcastReceiver, ReceiverDispatcher> holder - = mUnregisteredReceivers.get(context); - if (holder == null) { - holder = new HashMap<BroadcastReceiver, ReceiverDispatcher>(); - mUnregisteredReceivers.put(context, holder); - } - RuntimeException ex = new IllegalArgumentException( - "Originally unregistered here:"); - ex.fillInStackTrace(); - rd.setUnregisterLocation(ex); - holder.put(r, rd); - } - return rd.getIIntentReceiver(); - } - } - HashMap<BroadcastReceiver, ReceiverDispatcher> holder - = mUnregisteredReceivers.get(context); - if (holder != null) { - rd = holder.get(r); - if (rd != null) { - RuntimeException ex = rd.getUnregisterLocation(); - throw new IllegalArgumentException( - "Unregistering Receiver " + r - + " that was already unregistered", ex); - } - } - if (context == null) { - throw new IllegalStateException("Unbinding Receiver " + r - + " from Context that is no longer in use: " + context); - } else { - throw new IllegalArgumentException("Receiver not registered: " + r); - } - - } - } - - static final class ReceiverDispatcher { - - final static class InnerReceiver extends IIntentReceiver.Stub { - final WeakReference<ReceiverDispatcher> mDispatcher; - final ReceiverDispatcher mStrongRef; - - InnerReceiver(ReceiverDispatcher rd, boolean strong) { - mDispatcher = new WeakReference<ReceiverDispatcher>(rd); - mStrongRef = strong ? rd : null; - } - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean ordered, boolean sticky) { - ReceiverDispatcher rd = mDispatcher.get(); - if (DEBUG_BROADCAST) { - int seq = intent.getIntExtra("seq", -1); - Slog.i(TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq - + " to " + (rd != null ? rd.mReceiver : null)); - } - if (rd != null) { - rd.performReceive(intent, resultCode, data, extras, - ordered, sticky); - } else { - // The activity manager dispatched a broadcast to a registered - // receiver in this process, but before it could be delivered the - // receiver was unregistered. Acknowledge the broadcast on its - // behalf so that the system's broadcast sequence can continue. - if (DEBUG_BROADCAST) Slog.i(TAG, - "Finishing broadcast to unregistered receiver"); - IActivityManager mgr = ActivityManagerNative.getDefault(); - try { - mgr.finishReceiver(this, resultCode, data, extras, false); - } catch (RemoteException e) { - Slog.w(TAG, "Couldn't finish broadcast to unregistered receiver"); - } - } - } - } - - final IIntentReceiver.Stub mIIntentReceiver; - final BroadcastReceiver mReceiver; - final Context mContext; - final Handler mActivityThread; - final Instrumentation mInstrumentation; - final boolean mRegistered; - final IntentReceiverLeaked mLocation; - RuntimeException mUnregisterLocation; - - final class Args implements Runnable { - private Intent mCurIntent; - private int mCurCode; - private String mCurData; - private Bundle mCurMap; - private boolean mCurOrdered; - private boolean mCurSticky; - - public void run() { - BroadcastReceiver receiver = mReceiver; - if (DEBUG_BROADCAST) { - int seq = mCurIntent.getIntExtra("seq", -1); - Slog.i(TAG, "Dispatching broadcast " + mCurIntent.getAction() - + " seq=" + seq + " to " + mReceiver); - Slog.i(TAG, " mRegistered=" + mRegistered - + " mCurOrdered=" + mCurOrdered); - } - - IActivityManager mgr = ActivityManagerNative.getDefault(); - Intent intent = mCurIntent; - mCurIntent = null; - - if (receiver == null) { - if (mRegistered && mCurOrdered) { - try { - if (DEBUG_BROADCAST) Slog.i(TAG, - "Finishing null broadcast to " + mReceiver); - mgr.finishReceiver(mIIntentReceiver, - mCurCode, mCurData, mCurMap, false); - } catch (RemoteException ex) { - } - } - return; - } - - try { - ClassLoader cl = mReceiver.getClass().getClassLoader(); - intent.setExtrasClassLoader(cl); - if (mCurMap != null) { - mCurMap.setClassLoader(cl); - } - receiver.setOrderedHint(true); - receiver.setResult(mCurCode, mCurData, mCurMap); - receiver.clearAbortBroadcast(); - receiver.setOrderedHint(mCurOrdered); - receiver.setInitialStickyHint(mCurSticky); - receiver.onReceive(mContext, intent); - } catch (Exception e) { - if (mRegistered && mCurOrdered) { - try { - if (DEBUG_BROADCAST) Slog.i(TAG, - "Finishing failed broadcast to " + mReceiver); - mgr.finishReceiver(mIIntentReceiver, - mCurCode, mCurData, mCurMap, false); - } catch (RemoteException ex) { - } - } - if (mInstrumentation == null || - !mInstrumentation.onException(mReceiver, e)) { - throw new RuntimeException( - "Error receiving broadcast " + intent - + " in " + mReceiver, e); - } - } - if (mRegistered && mCurOrdered) { - try { - if (DEBUG_BROADCAST) Slog.i(TAG, - "Finishing broadcast to " + mReceiver); - mgr.finishReceiver(mIIntentReceiver, - receiver.getResultCode(), - receiver.getResultData(), - receiver.getResultExtras(false), - receiver.getAbortBroadcast()); - } catch (RemoteException ex) { - } - } - } - } - - ReceiverDispatcher(BroadcastReceiver receiver, Context context, - Handler activityThread, Instrumentation instrumentation, - boolean registered) { - if (activityThread == null) { - throw new NullPointerException("Handler must not be null"); - } - - mIIntentReceiver = new InnerReceiver(this, !registered); - mReceiver = receiver; - mContext = context; - mActivityThread = activityThread; - mInstrumentation = instrumentation; - mRegistered = registered; - mLocation = new IntentReceiverLeaked(null); - mLocation.fillInStackTrace(); - } - - void validate(Context context, Handler activityThread) { - if (mContext != context) { - throw new IllegalStateException( - "Receiver " + mReceiver + - " registered with differing Context (was " + - mContext + " now " + context + ")"); - } - if (mActivityThread != activityThread) { - throw new IllegalStateException( - "Receiver " + mReceiver + - " registered with differing handler (was " + - mActivityThread + " now " + activityThread + ")"); - } - } - - IntentReceiverLeaked getLocation() { - return mLocation; - } - - BroadcastReceiver getIntentReceiver() { - return mReceiver; - } - - IIntentReceiver getIIntentReceiver() { - return mIIntentReceiver; - } - - void setUnregisterLocation(RuntimeException ex) { - mUnregisterLocation = ex; - } - - RuntimeException getUnregisterLocation() { - return mUnregisterLocation; - } - - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean ordered, boolean sticky) { - if (DEBUG_BROADCAST) { - int seq = intent.getIntExtra("seq", -1); - Slog.i(TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq - + " to " + mReceiver); - } - Args args = new Args(); - args.mCurIntent = intent; - args.mCurCode = resultCode; - args.mCurData = data; - args.mCurMap = extras; - args.mCurOrdered = ordered; - args.mCurSticky = sticky; - if (!mActivityThread.post(args)) { - if (mRegistered && ordered) { - IActivityManager mgr = ActivityManagerNative.getDefault(); - try { - if (DEBUG_BROADCAST) Slog.i(TAG, - "Finishing sync broadcast to " + mReceiver); - mgr.finishReceiver(mIIntentReceiver, args.mCurCode, - args.mCurData, args.mCurMap, false); - } catch (RemoteException ex) { - } - } - } - } - - } - - public final IServiceConnection getServiceDispatcher(ServiceConnection c, - Context context, Handler handler, int flags) { - synchronized (mServices) { - ServiceDispatcher sd = null; - HashMap<ServiceConnection, ServiceDispatcher> map = mServices.get(context); - if (map != null) { - sd = map.get(c); - } - if (sd == null) { - sd = new ServiceDispatcher(c, context, handler, flags); - if (map == null) { - map = new HashMap<ServiceConnection, ServiceDispatcher>(); - mServices.put(context, map); - } - map.put(c, sd); - } else { - sd.validate(context, handler); - } - return sd.getIServiceConnection(); - } - } - - public final IServiceConnection forgetServiceDispatcher(Context context, - ServiceConnection c) { - synchronized (mServices) { - HashMap<ServiceConnection, ServiceDispatcher> map - = mServices.get(context); - ServiceDispatcher sd = null; - if (map != null) { - sd = map.get(c); - if (sd != null) { - map.remove(c); - sd.doForget(); - if (map.size() == 0) { - mServices.remove(context); - } - if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) { - HashMap<ServiceConnection, ServiceDispatcher> holder - = mUnboundServices.get(context); - if (holder == null) { - holder = new HashMap<ServiceConnection, ServiceDispatcher>(); - mUnboundServices.put(context, holder); - } - RuntimeException ex = new IllegalArgumentException( - "Originally unbound here:"); - ex.fillInStackTrace(); - sd.setUnbindLocation(ex); - holder.put(c, sd); - } - return sd.getIServiceConnection(); - } - } - HashMap<ServiceConnection, ServiceDispatcher> holder - = mUnboundServices.get(context); - if (holder != null) { - sd = holder.get(c); - if (sd != null) { - RuntimeException ex = sd.getUnbindLocation(); - throw new IllegalArgumentException( - "Unbinding Service " + c - + " that was already unbound", ex); - } - } - if (context == null) { - throw new IllegalStateException("Unbinding Service " + c - + " from Context that is no longer in use: " + context); - } else { - throw new IllegalArgumentException("Service not registered: " + c); - } - } - } - - static final class ServiceDispatcher { - private final InnerConnection mIServiceConnection; - private final ServiceConnection mConnection; - private final Context mContext; - private final Handler mActivityThread; - private final ServiceConnectionLeaked mLocation; - private final int mFlags; - - private RuntimeException mUnbindLocation; - - private boolean mDied; - - private static class ConnectionInfo { - IBinder binder; - IBinder.DeathRecipient deathMonitor; - } - - private static class InnerConnection extends IServiceConnection.Stub { - final WeakReference<ServiceDispatcher> mDispatcher; - - InnerConnection(ServiceDispatcher sd) { - mDispatcher = new WeakReference<ServiceDispatcher>(sd); - } - - public void connected(ComponentName name, IBinder service) throws RemoteException { - ServiceDispatcher sd = mDispatcher.get(); - if (sd != null) { - sd.connected(name, service); - } - } - } - - private final HashMap<ComponentName, ConnectionInfo> mActiveConnections - = new HashMap<ComponentName, ConnectionInfo>(); - - ServiceDispatcher(ServiceConnection conn, - Context context, Handler activityThread, int flags) { - mIServiceConnection = new InnerConnection(this); - mConnection = conn; - mContext = context; - mActivityThread = activityThread; - mLocation = new ServiceConnectionLeaked(null); - mLocation.fillInStackTrace(); - mFlags = flags; - } - - void validate(Context context, Handler activityThread) { - if (mContext != context) { - throw new RuntimeException( - "ServiceConnection " + mConnection + - " registered with differing Context (was " + - mContext + " now " + context + ")"); - } - if (mActivityThread != activityThread) { - throw new RuntimeException( - "ServiceConnection " + mConnection + - " registered with differing handler (was " + - mActivityThread + " now " + activityThread + ")"); - } - } - - void doForget() { - synchronized(this) { - Iterator<ConnectionInfo> it = mActiveConnections.values().iterator(); - while (it.hasNext()) { - ConnectionInfo ci = it.next(); - ci.binder.unlinkToDeath(ci.deathMonitor, 0); - } - mActiveConnections.clear(); - } - } - - ServiceConnectionLeaked getLocation() { - return mLocation; - } - - ServiceConnection getServiceConnection() { - return mConnection; - } - - IServiceConnection getIServiceConnection() { - return mIServiceConnection; - } - - int getFlags() { - return mFlags; - } - - void setUnbindLocation(RuntimeException ex) { - mUnbindLocation = ex; - } - - RuntimeException getUnbindLocation() { - return mUnbindLocation; - } - - public void connected(ComponentName name, IBinder service) { - if (mActivityThread != null) { - mActivityThread.post(new RunConnection(name, service, 0)); - } else { - doConnected(name, service); - } - } - - public void death(ComponentName name, IBinder service) { - ConnectionInfo old; - - synchronized (this) { - mDied = true; - old = mActiveConnections.remove(name); - if (old == null || old.binder != service) { - // Death for someone different than who we last - // reported... just ignore it. - return; - } - old.binder.unlinkToDeath(old.deathMonitor, 0); - } - - if (mActivityThread != null) { - mActivityThread.post(new RunConnection(name, service, 1)); - } else { - doDeath(name, service); - } - } - - public void doConnected(ComponentName name, IBinder service) { - ConnectionInfo old; - ConnectionInfo info; - - synchronized (this) { - old = mActiveConnections.get(name); - if (old != null && old.binder == service) { - // Huh, already have this one. Oh well! - return; - } - - if (service != null) { - // A new service is being connected... set it all up. - mDied = false; - info = new ConnectionInfo(); - info.binder = service; - info.deathMonitor = new DeathMonitor(name, service); - try { - service.linkToDeath(info.deathMonitor, 0); - mActiveConnections.put(name, info); - } catch (RemoteException e) { - // This service was dead before we got it... just - // don't do anything with it. - mActiveConnections.remove(name); - return; - } - - } else { - // The named service is being disconnected... clean up. - mActiveConnections.remove(name); - } - - if (old != null) { - old.binder.unlinkToDeath(old.deathMonitor, 0); - } - } - - // If there was an old service, it is not disconnected. - if (old != null) { - mConnection.onServiceDisconnected(name); - } - // If there is a new service, it is now connected. - if (service != null) { - mConnection.onServiceConnected(name, service); - } - } - - public void doDeath(ComponentName name, IBinder service) { - mConnection.onServiceDisconnected(name); - } - - private final class RunConnection implements Runnable { - RunConnection(ComponentName name, IBinder service, int command) { - mName = name; - mService = service; - mCommand = command; - } - - public void run() { - if (mCommand == 0) { - doConnected(mName, mService); - } else if (mCommand == 1) { - doDeath(mName, mService); - } - } - - final ComponentName mName; - final IBinder mService; - final int mCommand; - } + static IPackageManager sPackageManager; - private final class DeathMonitor implements IBinder.DeathRecipient - { - DeathMonitor(ComponentName name, IBinder service) { - mName = name; - mService = service; - } + final ApplicationThread mAppThread = new ApplicationThread(); + final Looper mLooper = Looper.myLooper(); + final H mH = new H(); + final HashMap<IBinder, ActivityClientRecord> mActivities + = new HashMap<IBinder, ActivityClientRecord>(); + // List of new activities (via ActivityRecord.nextIdle) that should + // be reported when next we idle. + ActivityClientRecord mNewActivities = null; + // Number of activities that are currently visible on-screen. + int mNumVisibleActivities = 0; + final HashMap<IBinder, Service> mServices + = new HashMap<IBinder, Service>(); + AppBindData mBoundApplication; + Configuration mConfiguration; + Configuration mResConfiguration; + Application mInitialApplication; + final ArrayList<Application> mAllApplications + = new ArrayList<Application>(); + // set of instantiated backup agents, keyed by package name + final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>(); + static final ThreadLocal sThreadLocal = new ThreadLocal(); + Instrumentation mInstrumentation; + String mInstrumentationAppDir = null; + String mInstrumentationAppPackage = null; + String mInstrumentedAppDir = null; + boolean mSystemThread = false; + boolean mJitEnabled = false; - public void binderDied() { - death(mName, mService); - } + // These can be accessed by multiple threads; mPackages is the lock. + // XXX For now we keep around information about all packages we have + // seen, not removing entries from this map. + final HashMap<String, WeakReference<LoadedApk>> mPackages + = new HashMap<String, WeakReference<LoadedApk>>(); + final HashMap<String, WeakReference<LoadedApk>> mResourcePackages + = new HashMap<String, WeakReference<LoadedApk>>(); + Display mDisplay = null; + DisplayMetrics mDisplayMetrics = null; + final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources + = new HashMap<ResourcesKey, WeakReference<Resources> >(); + final ArrayList<ActivityClientRecord> mRelaunchingActivities + = new ArrayList<ActivityClientRecord>(); + Configuration mPendingConfiguration = null; - final ComponentName mName; - final IBinder mService; - } - } - } + // The lock of mProviderMap protects the following variables. + final HashMap<String, ProviderClientRecord> mProviderMap + = new HashMap<String, ProviderClientRecord>(); + final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap + = new HashMap<IBinder, ProviderRefCount>(); + final HashMap<IBinder, ProviderClientRecord> mLocalProviders + = new HashMap<IBinder, ProviderClientRecord>(); - private static ContextImpl mSystemContext = null; + final GcIdler mGcIdler = new GcIdler(); + boolean mGcIdlerScheduled = false; - private static final class ActivityRecord { + private static final class ActivityClientRecord { IBinder token; int ident; Intent intent; @@ -1309,10 +195,10 @@ public final class ActivityThread { boolean hideForNow; Configuration newConfig; Configuration createdConfig; - ActivityRecord nextIdle; + ActivityClientRecord nextIdle; ActivityInfo activityInfo; - PackageInfo packageInfo; + LoadedApk packageInfo; List<ResultInfo> pendingResults; List<Intent> pendingIntents; @@ -1320,7 +206,7 @@ public final class ActivityThread { boolean startsNotResumed; boolean isForward; - ActivityRecord() { + ActivityClientRecord() { parent = null; embeddedID = null; paused = false; @@ -1339,12 +225,12 @@ public final class ActivityThread { } } - private final class ProviderRecord implements IBinder.DeathRecipient { + private final class ProviderClientRecord implements IBinder.DeathRecipient { final String mName; final IContentProvider mProvider; final ContentProvider mLocalProvider; - ProviderRecord(String name, IContentProvider provider, + ProviderClientRecord(String name, IContentProvider provider, ContentProvider localProvider) { mName = name; mProvider = provider; @@ -1421,7 +307,7 @@ public final class ActivityThread { } private static final class AppBindData { - PackageInfo info; + LoadedApk info; String processName; ApplicationInfo appInfo; List<ProviderInfo> providers; @@ -1511,7 +397,7 @@ public final class ActivityThread { public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) { - ActivityRecord r = new ActivityRecord(); + ActivityClientRecord r = new ActivityClientRecord(); r.token = token; r.ident = ident; @@ -1531,7 +417,7 @@ public final class ActivityThread { public final void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, int configChanges, boolean notResumed, Configuration config) { - ActivityRecord r = new ActivityRecord(); + ActivityClientRecord r = new ActivityClientRecord(); r.token = token; r.pendingResults = pendingResults; @@ -2028,14 +914,14 @@ public final class ActivityThread { public void handleMessage(Message msg) { switch (msg.what) { case LAUNCH_ACTIVITY: { - ActivityRecord r = (ActivityRecord)msg.obj; + ActivityClientRecord r = (ActivityClientRecord)msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo); handleLaunchActivity(r, null); } break; case RELAUNCH_ACTIVITY: { - ActivityRecord r = (ActivityRecord)msg.obj; + ActivityClientRecord r = (ActivityClientRecord)msg.obj; handleRelaunchActivity(r, msg.arg1); } break; case PAUSE_ACTIVITY: @@ -2157,11 +1043,11 @@ public final class ActivityThread { private final class Idler implements MessageQueue.IdleHandler { public final boolean queueIdle() { - ActivityRecord a = mNewActivities; + ActivityClientRecord a = mNewActivities; if (a != null) { mNewActivities = null; IActivityManager am = ActivityManagerNative.getDefault(); - ActivityRecord prev; + ActivityClientRecord prev; do { if (localLOGV) Slog.v( TAG, "Reporting idle of " + a + @@ -2217,71 +1103,132 @@ public final class ActivityThread { } } - static IPackageManager sPackageManager; + public static final ActivityThread currentActivityThread() { + return (ActivityThread)sThreadLocal.get(); + } - final ApplicationThread mAppThread = new ApplicationThread(); - final Looper mLooper = Looper.myLooper(); - final H mH = new H(); - final HashMap<IBinder, ActivityRecord> mActivities - = new HashMap<IBinder, ActivityRecord>(); - // List of new activities (via ActivityRecord.nextIdle) that should - // be reported when next we idle. - ActivityRecord mNewActivities = null; - // Number of activities that are currently visible on-screen. - int mNumVisibleActivities = 0; - final HashMap<IBinder, Service> mServices - = new HashMap<IBinder, Service>(); - AppBindData mBoundApplication; - Configuration mConfiguration; - Configuration mResConfiguration; - Application mInitialApplication; - final ArrayList<Application> mAllApplications - = new ArrayList<Application>(); - // set of instantiated backup agents, keyed by package name - final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>(); - static final ThreadLocal sThreadLocal = new ThreadLocal(); - Instrumentation mInstrumentation; - String mInstrumentationAppDir = null; - String mInstrumentationAppPackage = null; - String mInstrumentedAppDir = null; - boolean mSystemThread = false; - boolean mJitEnabled = false; + public static final String currentPackageName() { + ActivityThread am = currentActivityThread(); + return (am != null && am.mBoundApplication != null) + ? am.mBoundApplication.processName : null; + } - // These can be accessed by multiple threads; mPackages is the lock. - // XXX For now we keep around information about all packages we have - // seen, not removing entries from this map. - final HashMap<String, WeakReference<PackageInfo>> mPackages - = new HashMap<String, WeakReference<PackageInfo>>(); - final HashMap<String, WeakReference<PackageInfo>> mResourcePackages - = new HashMap<String, WeakReference<PackageInfo>>(); - Display mDisplay = null; - DisplayMetrics mDisplayMetrics = null; - final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources - = new HashMap<ResourcesKey, WeakReference<Resources> >(); - final ArrayList<ActivityRecord> mRelaunchingActivities - = new ArrayList<ActivityRecord>(); - Configuration mPendingConfiguration = null; + public static final Application currentApplication() { + ActivityThread am = currentActivityThread(); + return am != null ? am.mInitialApplication : null; + } - // The lock of mProviderMap protects the following variables. - final HashMap<String, ProviderRecord> mProviderMap - = new HashMap<String, ProviderRecord>(); - final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap - = new HashMap<IBinder, ProviderRefCount>(); - final HashMap<IBinder, ProviderRecord> mLocalProviders - = new HashMap<IBinder, ProviderRecord>(); + public static IPackageManager getPackageManager() { + if (sPackageManager != null) { + //Slog.v("PackageManager", "returning cur default = " + sPackageManager); + return sPackageManager; + } + IBinder b = ServiceManager.getService("package"); + //Slog.v("PackageManager", "default service binder = " + b); + sPackageManager = IPackageManager.Stub.asInterface(b); + //Slog.v("PackageManager", "default service = " + sPackageManager); + return sPackageManager; + } - final GcIdler mGcIdler = new GcIdler(); - boolean mGcIdlerScheduled = false; + DisplayMetrics getDisplayMetricsLocked(boolean forceUpdate) { + if (mDisplayMetrics != null && !forceUpdate) { + return mDisplayMetrics; + } + if (mDisplay == null) { + WindowManager wm = WindowManagerImpl.getDefault(); + mDisplay = wm.getDefaultDisplay(); + } + DisplayMetrics metrics = mDisplayMetrics = new DisplayMetrics(); + mDisplay.getMetrics(metrics); + //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h=" + // + metrics.heightPixels + " den=" + metrics.density + // + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi); + return metrics; + } + + /** + * Creates the top level Resources for applications with the given compatibility info. + * + * @param resDir the resource directory. + * @param compInfo the compability info. It will use the default compatibility info when it's + * null. + */ + Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) { + ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale); + Resources r; + synchronized (mPackages) { + // Resources is app scale dependent. + if (false) { + Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + + compInfo.applicationScale); + } + WeakReference<Resources> wr = mActiveResources.get(key); + r = wr != null ? wr.get() : null; + //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate()); + if (r != null && r.getAssets().isUpToDate()) { + if (false) { + Slog.w(TAG, "Returning cached resources " + r + " " + resDir + + ": appScale=" + r.getCompatibilityInfo().applicationScale); + } + return r; + } + } + + //if (r != null) { + // Slog.w(TAG, "Throwing away out-of-date resources!!!! " + // + r + " " + resDir); + //} + + AssetManager assets = new AssetManager(); + if (assets.addAssetPath(resDir) == 0) { + return null; + } + + //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); + DisplayMetrics metrics = getDisplayMetricsLocked(false); + r = new Resources(assets, metrics, getConfiguration(), compInfo); + if (false) { + Slog.i(TAG, "Created app resources " + resDir + " " + r + ": " + + r.getConfiguration() + " appScale=" + + r.getCompatibilityInfo().applicationScale); + } + + synchronized (mPackages) { + WeakReference<Resources> wr = mActiveResources.get(key); + Resources existing = wr != null ? wr.get() : null; + if (existing != null && existing.getAssets().isUpToDate()) { + // Someone else already created the resources while we were + // unlocked; go ahead and use theirs. + r.getAssets().close(); + return existing; + } + + // XXX need to remove entries when weak references go away + mActiveResources.put(key, new WeakReference<Resources>(r)); + return r; + } + } + + /** + * Creates the top level resources for the given package. + */ + Resources getTopLevelResources(String resDir, LoadedApk pkgInfo) { + return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo); + } + + final Handler getHandler() { + return mH; + } - public final PackageInfo getPackageInfo(String packageName, int flags) { + public final LoadedApk getPackageInfo(String packageName, int flags) { synchronized (mPackages) { - WeakReference<PackageInfo> ref; + WeakReference<LoadedApk> ref; if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) { ref = mPackages.get(packageName); } else { ref = mResourcePackages.get(packageName); } - PackageInfo packageInfo = ref != null ? ref.get() : null; + LoadedApk packageInfo = ref != null ? ref.get() : null; //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo); //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir // + ": " + packageInfo.mResources.getAssets().isUpToDate()); @@ -2313,7 +1260,7 @@ public final class ActivityThread { return null; } - public final PackageInfo getPackageInfo(ApplicationInfo ai, int flags) { + public final LoadedApk getPackageInfo(ApplicationInfo ai, int flags) { boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0; boolean securityViolation = includeCode && ai.uid != 0 && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null @@ -2335,20 +1282,20 @@ public final class ActivityThread { return getPackageInfo(ai, null, securityViolation, includeCode); } - public final PackageInfo getPackageInfoNoCheck(ApplicationInfo ai) { + public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai) { return getPackageInfo(ai, null, false, true); } - private final PackageInfo getPackageInfo(ApplicationInfo aInfo, + private final LoadedApk getPackageInfo(ApplicationInfo aInfo, ClassLoader baseLoader, boolean securityViolation, boolean includeCode) { synchronized (mPackages) { - WeakReference<PackageInfo> ref; + WeakReference<LoadedApk> ref; if (includeCode) { ref = mPackages.get(aInfo.packageName); } else { ref = mResourcePackages.get(aInfo.packageName); } - PackageInfo packageInfo = ref != null ? ref.get() : null; + LoadedApk packageInfo = ref != null ? ref.get() : null; if (packageInfo == null || (packageInfo.mResources != null && !packageInfo.mResources.getAssets().isUpToDate())) { if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package " @@ -2357,15 +1304,15 @@ public final class ActivityThread { ? mBoundApplication.processName : null) + ")"); packageInfo = - new PackageInfo(this, aInfo, this, baseLoader, + new LoadedApk(this, aInfo, this, baseLoader, securityViolation, includeCode && (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0); if (includeCode) { mPackages.put(aInfo.packageName, - new WeakReference<PackageInfo>(packageInfo)); + new WeakReference<LoadedApk>(packageInfo)); } else { mResourcePackages.put(aInfo.packageName, - new WeakReference<PackageInfo>(packageInfo)); + new WeakReference<LoadedApk>(packageInfo)); } } return packageInfo; @@ -2414,7 +1361,7 @@ public final class ActivityThread { if (mSystemContext == null) { ContextImpl context = ContextImpl.createSystemContext(this); - PackageInfo info = new PackageInfo(this, "android", context, null); + LoadedApk info = new LoadedApk(this, "android", context, null); context.init(info, null, this); context.getResources().updateConfiguration( getConfiguration(), getDisplayMetricsLocked(false)); @@ -2429,7 +1376,7 @@ public final class ActivityThread { public void installSystemApplicationInfo(ApplicationInfo info) { synchronized (this) { ContextImpl context = getSystemContext(); - context.init(new PackageInfo(this, "android", context, info), null, this); + context.init(new LoadedApk(this, "android", context, info), null, this); } } @@ -2481,7 +1428,7 @@ public final class ActivityThread { public final Activity startActivityNow(Activity parent, String id, Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state, Object lastNonConfigurationInstance) { - ActivityRecord r = new ActivityRecord(); + ActivityClientRecord r = new ActivityClientRecord(); r.token = token; r.ident = 0; r.intent = intent; @@ -2552,7 +1499,7 @@ public final class ActivityThread { queueOrSendMessage(H.CLEAN_UP_CONTEXT, cci); } - private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) { + private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; @@ -2671,7 +1618,7 @@ public final class ActivityThread { return activity; } - private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) { + private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -2731,7 +1678,7 @@ public final class ActivityThread { } } - private final void deliverNewIntents(ActivityRecord r, + private final void deliverNewIntents(ActivityClientRecord r, List<Intent> intents) { final int N = intents.size(); for (int i=0; i<N; i++) { @@ -2743,7 +1690,7 @@ public final class ActivityThread { public final void performNewIntents(IBinder token, List<Intent> intents) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); if (r != null) { final boolean resumed = !r.paused; if (resumed) { @@ -2767,7 +1714,7 @@ public final class ActivityThread { String component = data.intent.getComponent().getClassName(); - PackageInfo packageInfo = getPackageInfoNoCheck( + LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo); IActivityManager mgr = ActivityManagerNative.getDefault(); @@ -2851,7 +1798,7 @@ public final class ActivityThread { unscheduleGcIdler(); // instantiate the BackupAgent class named in the manifest - PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo); + LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo); String packageName = packageInfo.mPackageName; if (mBackupAgents.get(packageName) != null) { Slog.d(TAG, "BackupAgent " + " for " + packageName @@ -2913,7 +1860,7 @@ public final class ActivityThread { private final void handleDestroyBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data); - PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo); + LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo); String packageName = packageInfo.mPackageName; BackupAgent agent = mBackupAgents.get(packageName); if (agent != null) { @@ -2934,7 +1881,7 @@ public final class ActivityThread { // we are back active so skip it. unscheduleGcIdler(); - PackageInfo packageInfo = getPackageInfoNoCheck( + LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo); Service service = null; try { @@ -3098,9 +2045,9 @@ public final class ActivityThread { //Slog.i(TAG, "Running services: " + mServices); } - public final ActivityRecord performResumeActivity(IBinder token, + public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); if (localLOGV) Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); if (r != null && !r.activity.mFinished) { @@ -3142,7 +2089,7 @@ public final class ActivityThread { // we are back active so skip it. unscheduleGcIdler(); - ActivityRecord r = performResumeActivity(token, clearHide); + ActivityClientRecord r = performResumeActivity(token, clearHide); if (r != null) { final Activity a = r.activity; @@ -3241,7 +2188,7 @@ public final class ActivityThread { private int mThumbnailWidth = -1; private int mThumbnailHeight = -1; - private final Bitmap createThumbnailBitmap(ActivityRecord r) { + private final Bitmap createThumbnailBitmap(ActivityClientRecord r) { Bitmap thumbnail = null; try { int w = mThumbnailWidth; @@ -3279,7 +2226,7 @@ public final class ActivityThread { private final void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); if (r != null) { //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r); if (userLeaving) { @@ -3297,17 +2244,17 @@ public final class ActivityThread { } } - final void performUserLeavingActivity(ActivityRecord r) { + final void performUserLeavingActivity(ActivityClientRecord r) { mInstrumentation.callActivityOnUserLeaving(r.activity); } final Bundle performPauseActivity(IBinder token, boolean finished, boolean saveState) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); return r != null ? performPauseActivity(r, finished, saveState) : null; } - final Bundle performPauseActivity(ActivityRecord r, boolean finished, + final Bundle performPauseActivity(ActivityClientRecord r, boolean finished, boolean saveState) { if (r.paused) { if (r.activity.mFinished) { @@ -3358,7 +2305,7 @@ public final class ActivityThread { } final void performStopActivity(IBinder token) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); performStopActivityInner(r, null, false); } @@ -3374,7 +2321,7 @@ public final class ActivityThread { } } - private final void performStopActivityInner(ActivityRecord r, + private final void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); if (r != null) { @@ -3425,7 +2372,7 @@ public final class ActivityThread { } } - private final void updateVisibility(ActivityRecord r, boolean show) { + private final void updateVisibility(ActivityClientRecord r, boolean show) { View v = r.activity.mDecor; if (v != null) { if (show) { @@ -3453,7 +2400,7 @@ public final class ActivityThread { } private final void handleStopActivity(IBinder token, boolean show, int configChanges) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); r.activity.mConfigChangeFlags |= configChanges; StopInfo info = new StopInfo(); @@ -3474,7 +2421,7 @@ public final class ActivityThread { } final void performRestartActivity(IBinder token) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); if (r.stopped) { r.activity.performRestart(); r.stopped = false; @@ -3482,7 +2429,7 @@ public final class ActivityThread { } private final void handleWindowVisibility(IBinder token, boolean show) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); if (!show && !r.stopped) { performStopActivityInner(r, null, show); } else if (show && r.stopped) { @@ -3500,7 +2447,7 @@ public final class ActivityThread { } } - private final void deliverResults(ActivityRecord r, List<ResultInfo> results) { + private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) { final int N = results.size(); for (int i=0; i<N; i++) { ResultInfo ri = results.get(i); @@ -3524,7 +2471,7 @@ public final class ActivityThread { } private final void handleSendResult(ResultData res) { - ActivityRecord r = mActivities.get(res.token); + ActivityClientRecord r = mActivities.get(res.token); if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r); if (r != null) { final boolean resumed = !r.paused; @@ -3563,13 +2510,13 @@ public final class ActivityThread { } } - public final ActivityRecord performDestroyActivity(IBinder token, boolean finishing) { + public final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing) { return performDestroyActivity(token, finishing, 0, false); } - private final ActivityRecord performDestroyActivity(IBinder token, boolean finishing, + private final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); if (localLOGV) Slog.v(TAG, "Performing finish of " + r); if (r != null) { r.activity.mConfigChangeFlags |= configChanges; @@ -3672,7 +2619,7 @@ public final class ActivityThread { private final void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance) { - ActivityRecord r = performDestroyActivity(token, finishing, + ActivityClientRecord r = performDestroyActivity(token, finishing, configChanges, getNonConfigInstance); if (r != null) { WindowManager wm = r.activity.getWindowManager(); @@ -3713,7 +2660,7 @@ public final class ActivityThread { } } - private final void handleRelaunchActivity(ActivityRecord tmp, int configChanges) { + private final void handleRelaunchActivity(ActivityClientRecord tmp, int configChanges) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -3732,7 +2679,7 @@ public final class ActivityThread { IBinder token = tmp.token; tmp = null; for (int i=0; i<N; i++) { - ActivityRecord r = mRelaunchingActivities.get(i); + ActivityClientRecord r = mRelaunchingActivities.get(i); if (r.token == token) { tmp = r; mRelaunchingActivities.remove(i); @@ -3774,7 +2721,7 @@ public final class ActivityThread { handleConfigurationChanged(changedConfig); } - ActivityRecord r = mActivities.get(tmp.token); + ActivityClientRecord r = mActivities.get(tmp.token); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r); if (r == null) { return; @@ -3818,7 +2765,7 @@ public final class ActivityThread { } private final void handleRequestThumbnail(IBinder token) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); Bitmap thumbnail = createThumbnailBitmap(r); CharSequence description = null; try { @@ -3845,9 +2792,9 @@ public final class ActivityThread { = new ArrayList<ComponentCallbacks>(); if (mActivities.size() > 0) { - Iterator<ActivityRecord> it = mActivities.values().iterator(); + Iterator<ActivityClientRecord> it = mActivities.values().iterator(); while (it.hasNext()) { - ActivityRecord ar = it.next(); + ActivityClientRecord ar = it.next(); Activity a = ar.activity; if (a != null) { if (!ar.activity.mFinished && (allActivities || @@ -3876,7 +2823,7 @@ public final class ActivityThread { } synchronized (mProviderMap) { if (mLocalProviders.size() > 0) { - Iterator<ProviderRecord> it = mLocalProviders.values().iterator(); + Iterator<ProviderClientRecord> it = mLocalProviders.values().iterator(); while (it.hasNext()) { callbacks.add(it.next().mLocalProvider); } @@ -4022,7 +2969,7 @@ public final class ActivityThread { } final void handleActivityConfigurationChanged(IBinder token) { - ActivityRecord r = mActivities.get(token); + ActivityClientRecord r = mActivities.get(token); if (r == null || r.activity == null) { return; } @@ -4059,7 +3006,7 @@ public final class ActivityThread { for (int i=packages.length-1; i>=0; i--) { //Slog.i(TAG, "Cleaning old package: " + packages[i]); if (!hasPkgInfo) { - WeakReference<PackageInfo> ref; + WeakReference<LoadedApk> ref; ref = mPackages.get(packages[i]); if (ref != null && ref.get() != null) { hasPkgInfo = true; @@ -4204,7 +3151,7 @@ public final class ActivityThread { instrApp.sourceDir = ii.sourceDir; instrApp.publicSourceDir = ii.publicSourceDir; instrApp.dataDir = ii.dataDir; - PackageInfo pi = getPackageInfo(instrApp, + LoadedApk pi = getPackageInfo(instrApp, appContext.getClassLoader(), false, true); ContextImpl instrContext = new ContextImpl(); instrContext.init(pi, null, this); @@ -4315,7 +3262,7 @@ public final class ActivityThread { private final IContentProvider getProvider(Context context, String name) { synchronized(mProviderMap) { - final ProviderRecord pr = mProviderMap.get(name); + final ProviderClientRecord pr = mProviderMap.get(name); if (pr != null) { return pr.mProvider; } @@ -4426,9 +3373,9 @@ public final class ActivityThread { String name = null; // remove the provider from mProviderMap - Iterator<ProviderRecord> iter = mProviderMap.values().iterator(); + Iterator<ProviderClientRecord> iter = mProviderMap.values().iterator(); while (iter.hasNext()) { - ProviderRecord pr = iter.next(); + ProviderClientRecord pr = iter.next(); IBinder myBinder = pr.mProvider.asBinder(); if (myBinder == providerBinder) { //find if its published by this process itself @@ -4453,10 +3400,10 @@ public final class ActivityThread { final void removeDeadProvider(String name, IContentProvider provider) { synchronized(mProviderMap) { - ProviderRecord pr = mProviderMap.get(name); + ProviderClientRecord pr = mProviderMap.get(name); if (pr.mProvider.asBinder() == provider.asBinder()) { Slog.i(TAG, "Removing dead content provider: " + name); - ProviderRecord removed = mProviderMap.remove(name); + ProviderClientRecord removed = mProviderMap.remove(name); if (removed != null) { removed.mProvider.asBinder().unlinkToDeath(removed, 0); } @@ -4465,10 +3412,10 @@ public final class ActivityThread { } final void removeDeadProviderLocked(String name, IContentProvider provider) { - ProviderRecord pr = mProviderMap.get(name); + ProviderClientRecord pr = mProviderMap.get(name); if (pr.mProvider.asBinder() == provider.asBinder()) { Slog.i(TAG, "Removing dead content provider: " + name); - ProviderRecord removed = mProviderMap.remove(name); + ProviderClientRecord removed = mProviderMap.remove(name); if (removed != null) { removed.mProvider.asBinder().unlinkToDeath(removed, 0); } @@ -4536,7 +3483,7 @@ public final class ActivityThread { // Cache the pointer for the remote provider. String names[] = PATTERN_SEMICOLON.split(info.authority); for (int i=0; i<names.length; i++) { - ProviderRecord pr = new ProviderRecord(names[i], provider, + ProviderClientRecord pr = new ProviderClientRecord(names[i], provider, localProvider); try { provider.asBinder().linkToDeath(pr, 0); @@ -4547,7 +3494,7 @@ public final class ActivityThread { } if (localProvider != null) { mLocalProviders.put(provider.asBinder(), - new ProviderRecord(null, provider, localProvider)); + new ProviderClientRecord(null, provider, localProvider)); } } diff --git a/core/java/android/app/AppGlobals.java b/core/java/android/app/AppGlobals.java new file mode 100644 index 0000000..9a39129 --- /dev/null +++ b/core/java/android/app/AppGlobals.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 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 android.app; + +import android.content.pm.IPackageManager; + +/** + * Special private access for certain globals related to a process. + * @hide + */ +public class AppGlobals { + /** + * Return the first Application object made in the process. + * NOTE: Only works on the main thread. + */ + public static Application getInitialApplication() { + return ActivityThread.currentApplication(); + } + + /** + * Return the package name of the first .apk loaded into the process. + * NOTE: Only works on the main thread. + */ + public static String getInitialPackage() { + return ActivityThread.currentPackageName(); + } + + /** + * Return the raw interface to the package manager. + * @return + */ + public static IPackageManager getPackageManager() { + return ActivityThread.getPackageManager(); + } +} diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index bcdfe59..fc9bcf7 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -173,7 +173,7 @@ class ContextImpl extends Context { new HashMap<File, SharedPreferencesImpl>(); private AudioManager mAudioManager; - /*package*/ ActivityThread.PackageInfo mPackageInfo; + /*package*/ LoadedApk mPackageInfo; private Resources mResources; /*package*/ ActivityThread mMainThread; private Context mOuterContext; @@ -696,7 +696,7 @@ class ContextImpl extends Context { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = new ActivityThread.PackageInfo.ReceiverDispatcher( + rd = new LoadedApk.ReceiverDispatcher( resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver(); } } @@ -739,7 +739,7 @@ class ContextImpl extends Context { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = new ActivityThread.PackageInfo.ReceiverDispatcher( + rd = new LoadedApk.ReceiverDispatcher( resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver(); } } @@ -795,7 +795,7 @@ class ContextImpl extends Context { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = new ActivityThread.PackageInfo.ReceiverDispatcher( + rd = new LoadedApk.ReceiverDispatcher( receiver, context, scheduler, null, true).getIIntentReceiver(); } } @@ -1425,7 +1425,7 @@ class ContextImpl extends Context { return new ContextImpl(mMainThread.getSystemContext()); } - ActivityThread.PackageInfo pi = + LoadedApk pi = mMainThread.getPackageInfo(packageName, flags); if (pi != null) { ContextImpl c = new ContextImpl(); @@ -1492,12 +1492,12 @@ class ContextImpl extends Context { mOuterContext = this; } - final void init(ActivityThread.PackageInfo packageInfo, + final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) { init(packageInfo, activityToken, mainThread, null); } - final void init(ActivityThread.PackageInfo packageInfo, + final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread, Resources container) { mPackageInfo = packageInfo; diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java new file mode 100644 index 0000000..0f98152 --- /dev/null +++ b/core/java/android/app/LoadedApk.java @@ -0,0 +1,1103 @@ +/* + * Copyright (C) 2010 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 android.app; + +import com.android.internal.util.ArrayUtils; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.IIntentReceiver; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.content.res.CompatibilityInfo; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.util.AndroidRuntimeException; +import android.util.Slog; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; + +final class IntentReceiverLeaked extends AndroidRuntimeException { + public IntentReceiverLeaked(String msg) { + super(msg); + } +} + +final class ServiceConnectionLeaked extends AndroidRuntimeException { + public ServiceConnectionLeaked(String msg) { + super(msg); + } +} + +/** + * Local state maintained about a currently loaded .apk. + * @hide + */ +final class LoadedApk { + + private final ActivityThread mActivityThread; + private final ApplicationInfo mApplicationInfo; + final String mPackageName; + private final String mAppDir; + private final String mResDir; + private final String[] mSharedLibraries; + private final String mDataDir; + private final File mDataDirFile; + private final ClassLoader mBaseClassLoader; + private final boolean mSecurityViolation; + private final boolean mIncludeCode; + Resources mResources; + private ClassLoader mClassLoader; + private Application mApplication; + CompatibilityInfo mCompatibilityInfo; + + private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers + = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); + private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers + = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); + private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices + = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); + private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices + = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); + + int mClientCount = 0; + + Application getApplication() { + return mApplication; + } + + public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, + ActivityThread mainThread, ClassLoader baseLoader, + boolean securityViolation, boolean includeCode) { + mActivityThread = activityThread; + mApplicationInfo = aInfo; + mPackageName = aInfo.packageName; + mAppDir = aInfo.sourceDir; + mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir + : aInfo.publicSourceDir; + mSharedLibraries = aInfo.sharedLibraryFiles; + mDataDir = aInfo.dataDir; + mDataDirFile = mDataDir != null ? new File(mDataDir) : null; + mBaseClassLoader = baseLoader; + mSecurityViolation = securityViolation; + mIncludeCode = includeCode; + mCompatibilityInfo = new CompatibilityInfo(aInfo); + + if (mAppDir == null) { + if (ActivityThread.mSystemContext == null) { + ActivityThread.mSystemContext = + ContextImpl.createSystemContext(mainThread); + ActivityThread.mSystemContext.getResources().updateConfiguration( + mainThread.getConfiguration(), + mainThread.getDisplayMetricsLocked(false)); + //Slog.i(TAG, "Created system resources " + // + mSystemContext.getResources() + ": " + // + mSystemContext.getResources().getConfiguration()); + } + mClassLoader = ActivityThread.mSystemContext.getClassLoader(); + mResources = ActivityThread.mSystemContext.getResources(); + } + } + + public LoadedApk(ActivityThread activityThread, String name, + Context systemContext, ApplicationInfo info) { + mActivityThread = activityThread; + mApplicationInfo = info != null ? info : new ApplicationInfo(); + mApplicationInfo.packageName = name; + mPackageName = name; + mAppDir = null; + mResDir = null; + mSharedLibraries = null; + mDataDir = null; + mDataDirFile = null; + mBaseClassLoader = null; + mSecurityViolation = false; + mIncludeCode = true; + mClassLoader = systemContext.getClassLoader(); + mResources = systemContext.getResources(); + mCompatibilityInfo = new CompatibilityInfo(mApplicationInfo); + } + + public String getPackageName() { + return mPackageName; + } + + public ApplicationInfo getApplicationInfo() { + return mApplicationInfo; + } + + public boolean isSecurityViolation() { + return mSecurityViolation; + } + + /** + * Gets the array of shared libraries that are listed as + * used by the given package. + * + * @param packageName the name of the package (note: not its + * file name) + * @return null-ok; the array of shared libraries, each one + * a fully-qualified path + */ + private static String[] getLibrariesFor(String packageName) { + ApplicationInfo ai = null; + try { + ai = ActivityThread.getPackageManager().getApplicationInfo(packageName, + PackageManager.GET_SHARED_LIBRARY_FILES); + } catch (RemoteException e) { + throw new AssertionError(e); + } + + if (ai == null) { + return null; + } + + return ai.sharedLibraryFiles; + } + + /** + * Combines two arrays (of library names) such that they are + * concatenated in order but are devoid of duplicates. The + * result is a single string with the names of the libraries + * separated by colons, or <code>null</code> if both lists + * were <code>null</code> or empty. + * + * @param list1 null-ok; the first list + * @param list2 null-ok; the second list + * @return null-ok; the combination + */ + private static String combineLibs(String[] list1, String[] list2) { + StringBuilder result = new StringBuilder(300); + boolean first = true; + + if (list1 != null) { + for (String s : list1) { + if (first) { + first = false; + } else { + result.append(':'); + } + result.append(s); + } + } + + // Only need to check for duplicates if list1 was non-empty. + boolean dupCheck = !first; + + if (list2 != null) { + for (String s : list2) { + if (dupCheck && ArrayUtils.contains(list1, s)) { + continue; + } + + if (first) { + first = false; + } else { + result.append(':'); + } + result.append(s); + } + } + + return result.toString(); + } + + public ClassLoader getClassLoader() { + synchronized (this) { + if (mClassLoader != null) { + return mClassLoader; + } + + if (mIncludeCode && !mPackageName.equals("android")) { + String zip = mAppDir; + + /* + * The following is a bit of a hack to inject + * instrumentation into the system: If the app + * being started matches one of the instrumentation names, + * then we combine both the "instrumentation" and + * "instrumented" app into the path, along with the + * concatenation of both apps' shared library lists. + */ + + String instrumentationAppDir = + mActivityThread.mInstrumentationAppDir; + String instrumentationAppPackage = + mActivityThread.mInstrumentationAppPackage; + String instrumentedAppDir = + mActivityThread.mInstrumentedAppDir; + String[] instrumentationLibs = null; + + if (mAppDir.equals(instrumentationAppDir) + || mAppDir.equals(instrumentedAppDir)) { + zip = instrumentationAppDir + ":" + instrumentedAppDir; + if (! instrumentedAppDir.equals(instrumentationAppDir)) { + instrumentationLibs = + getLibrariesFor(instrumentationAppPackage); + } + } + + if ((mSharedLibraries != null) || + (instrumentationLibs != null)) { + zip = + combineLibs(mSharedLibraries, instrumentationLibs) + + ':' + zip; + } + + /* + * With all the combination done (if necessary, actually + * create the class loader. + */ + + if (ActivityThread.localLOGV) Slog.v(ActivityThread.TAG, "Class path: " + zip); + + mClassLoader = + ApplicationLoaders.getDefault().getClassLoader( + zip, mDataDir, mBaseClassLoader); + initializeJavaContextClassLoader(); + } else { + if (mBaseClassLoader == null) { + mClassLoader = ClassLoader.getSystemClassLoader(); + } else { + mClassLoader = mBaseClassLoader; + } + } + return mClassLoader; + } + } + + /** + * Setup value for Thread.getContextClassLoader(). If the + * package will not run in in a VM with other packages, we set + * the Java context ClassLoader to the + * PackageInfo.getClassLoader value. However, if this VM can + * contain multiple packages, we intead set the Java context + * ClassLoader to a proxy that will warn about the use of Java + * context ClassLoaders and then fall through to use the + * system ClassLoader. + * + * <p> Note that this is similar to but not the same as the + * android.content.Context.getClassLoader(). While both + * context class loaders are typically set to the + * PathClassLoader used to load the package archive in the + * single application per VM case, a single Android process + * may contain several Contexts executing on one thread with + * their own logical ClassLoaders while the Java context + * ClassLoader is a thread local. This is why in the case when + * we have multiple packages per VM we do not set the Java + * context ClassLoader to an arbitrary but instead warn the + * user to set their own if we detect that they are using a + * Java library that expects it to be set. + */ + private void initializeJavaContextClassLoader() { + IPackageManager pm = ActivityThread.getPackageManager(); + android.content.pm.PackageInfo pi; + try { + pi = pm.getPackageInfo(mPackageName, 0); + } catch (RemoteException e) { + throw new AssertionError(e); + } + /* + * Two possible indications that this package could be + * sharing its virtual machine with other packages: + * + * 1.) the sharedUserId attribute is set in the manifest, + * indicating a request to share a VM with other + * packages with the same sharedUserId. + * + * 2.) the application element of the manifest has an + * attribute specifying a non-default process name, + * indicating the desire to run in another packages VM. + */ + boolean sharedUserIdSet = (pi.sharedUserId != null); + boolean processNameNotDefault = + (pi.applicationInfo != null && + !mPackageName.equals(pi.applicationInfo.processName)); + boolean sharable = (sharedUserIdSet || processNameNotDefault); + ClassLoader contextClassLoader = + (sharable) + ? new WarningContextClassLoader() + : mClassLoader; + Thread.currentThread().setContextClassLoader(contextClassLoader); + } + + private static class WarningContextClassLoader extends ClassLoader { + + private static boolean warned = false; + + private void warn(String methodName) { + if (warned) { + return; + } + warned = true; + Thread.currentThread().setContextClassLoader(getParent()); + Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " + + "The class loader returned by " + + "Thread.getContextClassLoader() may fail for processes " + + "that host multiple applications. You should explicitly " + + "specify a context class loader. For example: " + + "Thread.setContextClassLoader(getClass().getClassLoader());"); + } + + @Override public URL getResource(String resName) { + warn("getResource"); + return getParent().getResource(resName); + } + + @Override public Enumeration<URL> getResources(String resName) throws IOException { + warn("getResources"); + return getParent().getResources(resName); + } + + @Override public InputStream getResourceAsStream(String resName) { + warn("getResourceAsStream"); + return getParent().getResourceAsStream(resName); + } + + @Override public Class<?> loadClass(String className) throws ClassNotFoundException { + warn("loadClass"); + return getParent().loadClass(className); + } + + @Override public void setClassAssertionStatus(String cname, boolean enable) { + warn("setClassAssertionStatus"); + getParent().setClassAssertionStatus(cname, enable); + } + + @Override public void setPackageAssertionStatus(String pname, boolean enable) { + warn("setPackageAssertionStatus"); + getParent().setPackageAssertionStatus(pname, enable); + } + + @Override public void setDefaultAssertionStatus(boolean enable) { + warn("setDefaultAssertionStatus"); + getParent().setDefaultAssertionStatus(enable); + } + + @Override public void clearAssertionStatus() { + warn("clearAssertionStatus"); + getParent().clearAssertionStatus(); + } + } + + public String getAppDir() { + return mAppDir; + } + + public String getResDir() { + return mResDir; + } + + public String getDataDir() { + return mDataDir; + } + + public File getDataDirFile() { + return mDataDirFile; + } + + public AssetManager getAssets(ActivityThread mainThread) { + return getResources(mainThread).getAssets(); + } + + public Resources getResources(ActivityThread mainThread) { + if (mResources == null) { + mResources = mainThread.getTopLevelResources(mResDir, this); + } + return mResources; + } + + public Application makeApplication(boolean forceDefaultAppClass, + Instrumentation instrumentation) { + if (mApplication != null) { + return mApplication; + } + + Application app = null; + + String appClass = mApplicationInfo.className; + if (forceDefaultAppClass || (appClass == null)) { + appClass = "android.app.Application"; + } + + try { + java.lang.ClassLoader cl = getClassLoader(); + ContextImpl appContext = new ContextImpl(); + appContext.init(this, null, mActivityThread); + app = mActivityThread.mInstrumentation.newApplication( + cl, appClass, appContext); + appContext.setOuterContext(app); + } catch (Exception e) { + if (!mActivityThread.mInstrumentation.onException(app, e)) { + throw new RuntimeException( + "Unable to instantiate application " + appClass + + ": " + e.toString(), e); + } + } + mActivityThread.mAllApplications.add(app); + mApplication = app; + + if (instrumentation != null) { + try { + instrumentation.callApplicationOnCreate(app); + } catch (Exception e) { + if (!instrumentation.onException(app, e)) { + throw new RuntimeException( + "Unable to create application " + app.getClass().getName() + + ": " + e.toString(), e); + } + } + } + + return app; + } + + public void removeContextRegistrations(Context context, + String who, String what) { + HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = + mReceivers.remove(context); + if (rmap != null) { + Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator(); + while (it.hasNext()) { + LoadedApk.ReceiverDispatcher rd = it.next(); + IntentReceiverLeaked leak = new IntentReceiverLeaked( + what + " " + who + " has leaked IntentReceiver " + + rd.getIntentReceiver() + " that was " + + "originally registered here. Are you missing a " + + "call to unregisterReceiver()?"); + leak.setStackTrace(rd.getLocation().getStackTrace()); + Slog.e(ActivityThread.TAG, leak.getMessage(), leak); + try { + ActivityManagerNative.getDefault().unregisterReceiver( + rd.getIIntentReceiver()); + } catch (RemoteException e) { + // system crashed, nothing we can do + } + } + } + mUnregisteredReceivers.remove(context); + //Slog.i(TAG, "Receiver registrations: " + mReceivers); + HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = + mServices.remove(context); + if (smap != null) { + Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator(); + while (it.hasNext()) { + LoadedApk.ServiceDispatcher sd = it.next(); + ServiceConnectionLeaked leak = new ServiceConnectionLeaked( + what + " " + who + " has leaked ServiceConnection " + + sd.getServiceConnection() + " that was originally bound here"); + leak.setStackTrace(sd.getLocation().getStackTrace()); + Slog.e(ActivityThread.TAG, leak.getMessage(), leak); + try { + ActivityManagerNative.getDefault().unbindService( + sd.getIServiceConnection()); + } catch (RemoteException e) { + // system crashed, nothing we can do + } + sd.doForget(); + } + } + mUnboundServices.remove(context); + //Slog.i(TAG, "Service registrations: " + mServices); + } + + public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, + Context context, Handler handler, + Instrumentation instrumentation, boolean registered) { + synchronized (mReceivers) { + LoadedApk.ReceiverDispatcher rd = null; + HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; + if (registered) { + map = mReceivers.get(context); + if (map != null) { + rd = map.get(r); + } + } + if (rd == null) { + rd = new ReceiverDispatcher(r, context, handler, + instrumentation, registered); + if (registered) { + if (map == null) { + map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); + mReceivers.put(context, map); + } + map.put(r, rd); + } + } else { + rd.validate(context, handler); + } + return rd.getIIntentReceiver(); + } + } + + public IIntentReceiver forgetReceiverDispatcher(Context context, + BroadcastReceiver r) { + synchronized (mReceivers) { + HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); + LoadedApk.ReceiverDispatcher rd = null; + if (map != null) { + rd = map.get(r); + if (rd != null) { + map.remove(r); + if (map.size() == 0) { + mReceivers.remove(context); + } + if (r.getDebugUnregister()) { + HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder + = mUnregisteredReceivers.get(context); + if (holder == null) { + holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); + mUnregisteredReceivers.put(context, holder); + } + RuntimeException ex = new IllegalArgumentException( + "Originally unregistered here:"); + ex.fillInStackTrace(); + rd.setUnregisterLocation(ex); + holder.put(r, rd); + } + return rd.getIIntentReceiver(); + } + } + HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder + = mUnregisteredReceivers.get(context); + if (holder != null) { + rd = holder.get(r); + if (rd != null) { + RuntimeException ex = rd.getUnregisterLocation(); + throw new IllegalArgumentException( + "Unregistering Receiver " + r + + " that was already unregistered", ex); + } + } + if (context == null) { + throw new IllegalStateException("Unbinding Receiver " + r + + " from Context that is no longer in use: " + context); + } else { + throw new IllegalArgumentException("Receiver not registered: " + r); + } + + } + } + + static final class ReceiverDispatcher { + + final static class InnerReceiver extends IIntentReceiver.Stub { + final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; + final LoadedApk.ReceiverDispatcher mStrongRef; + + InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { + mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); + mStrongRef = strong ? rd : null; + } + public void performReceive(Intent intent, int resultCode, + String data, Bundle extras, boolean ordered, boolean sticky) { + LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); + if (ActivityThread.DEBUG_BROADCAST) { + int seq = intent.getIntExtra("seq", -1); + Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq + + " to " + (rd != null ? rd.mReceiver : null)); + } + if (rd != null) { + rd.performReceive(intent, resultCode, data, extras, + ordered, sticky); + } else { + // The activity manager dispatched a broadcast to a registered + // receiver in this process, but before it could be delivered the + // receiver was unregistered. Acknowledge the broadcast on its + // behalf so that the system's broadcast sequence can continue. + if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, + "Finishing broadcast to unregistered receiver"); + IActivityManager mgr = ActivityManagerNative.getDefault(); + try { + mgr.finishReceiver(this, resultCode, data, extras, false); + } catch (RemoteException e) { + Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); + } + } + } + } + + final IIntentReceiver.Stub mIIntentReceiver; + final BroadcastReceiver mReceiver; + final Context mContext; + final Handler mActivityThread; + final Instrumentation mInstrumentation; + final boolean mRegistered; + final IntentReceiverLeaked mLocation; + RuntimeException mUnregisterLocation; + + final class Args implements Runnable { + private Intent mCurIntent; + private int mCurCode; + private String mCurData; + private Bundle mCurMap; + private boolean mCurOrdered; + private boolean mCurSticky; + + public void run() { + BroadcastReceiver receiver = mReceiver; + if (ActivityThread.DEBUG_BROADCAST) { + int seq = mCurIntent.getIntExtra("seq", -1); + Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction() + + " seq=" + seq + " to " + mReceiver); + Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered + + " mCurOrdered=" + mCurOrdered); + } + + IActivityManager mgr = ActivityManagerNative.getDefault(); + Intent intent = mCurIntent; + mCurIntent = null; + + if (receiver == null) { + if (mRegistered && mCurOrdered) { + try { + if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, + "Finishing null broadcast to " + mReceiver); + mgr.finishReceiver(mIIntentReceiver, + mCurCode, mCurData, mCurMap, false); + } catch (RemoteException ex) { + } + } + return; + } + + try { + ClassLoader cl = mReceiver.getClass().getClassLoader(); + intent.setExtrasClassLoader(cl); + if (mCurMap != null) { + mCurMap.setClassLoader(cl); + } + receiver.setOrderedHint(true); + receiver.setResult(mCurCode, mCurData, mCurMap); + receiver.clearAbortBroadcast(); + receiver.setOrderedHint(mCurOrdered); + receiver.setInitialStickyHint(mCurSticky); + receiver.onReceive(mContext, intent); + } catch (Exception e) { + if (mRegistered && mCurOrdered) { + try { + if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, + "Finishing failed broadcast to " + mReceiver); + mgr.finishReceiver(mIIntentReceiver, + mCurCode, mCurData, mCurMap, false); + } catch (RemoteException ex) { + } + } + if (mInstrumentation == null || + !mInstrumentation.onException(mReceiver, e)) { + throw new RuntimeException( + "Error receiving broadcast " + intent + + " in " + mReceiver, e); + } + } + if (mRegistered && mCurOrdered) { + try { + if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, + "Finishing broadcast to " + mReceiver); + mgr.finishReceiver(mIIntentReceiver, + receiver.getResultCode(), + receiver.getResultData(), + receiver.getResultExtras(false), + receiver.getAbortBroadcast()); + } catch (RemoteException ex) { + } + } + } + } + + ReceiverDispatcher(BroadcastReceiver receiver, Context context, + Handler activityThread, Instrumentation instrumentation, + boolean registered) { + if (activityThread == null) { + throw new NullPointerException("Handler must not be null"); + } + + mIIntentReceiver = new InnerReceiver(this, !registered); + mReceiver = receiver; + mContext = context; + mActivityThread = activityThread; + mInstrumentation = instrumentation; + mRegistered = registered; + mLocation = new IntentReceiverLeaked(null); + mLocation.fillInStackTrace(); + } + + void validate(Context context, Handler activityThread) { + if (mContext != context) { + throw new IllegalStateException( + "Receiver " + mReceiver + + " registered with differing Context (was " + + mContext + " now " + context + ")"); + } + if (mActivityThread != activityThread) { + throw new IllegalStateException( + "Receiver " + mReceiver + + " registered with differing handler (was " + + mActivityThread + " now " + activityThread + ")"); + } + } + + IntentReceiverLeaked getLocation() { + return mLocation; + } + + BroadcastReceiver getIntentReceiver() { + return mReceiver; + } + + IIntentReceiver getIIntentReceiver() { + return mIIntentReceiver; + } + + void setUnregisterLocation(RuntimeException ex) { + mUnregisterLocation = ex; + } + + RuntimeException getUnregisterLocation() { + return mUnregisterLocation; + } + + public void performReceive(Intent intent, int resultCode, + String data, Bundle extras, boolean ordered, boolean sticky) { + if (ActivityThread.DEBUG_BROADCAST) { + int seq = intent.getIntExtra("seq", -1); + Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq + + " to " + mReceiver); + } + Args args = new Args(); + args.mCurIntent = intent; + args.mCurCode = resultCode; + args.mCurData = data; + args.mCurMap = extras; + args.mCurOrdered = ordered; + args.mCurSticky = sticky; + if (!mActivityThread.post(args)) { + if (mRegistered && ordered) { + IActivityManager mgr = ActivityManagerNative.getDefault(); + try { + if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, + "Finishing sync broadcast to " + mReceiver); + mgr.finishReceiver(mIIntentReceiver, args.mCurCode, + args.mCurData, args.mCurMap, false); + } catch (RemoteException ex) { + } + } + } + } + + } + + public final IServiceConnection getServiceDispatcher(ServiceConnection c, + Context context, Handler handler, int flags) { + synchronized (mServices) { + LoadedApk.ServiceDispatcher sd = null; + HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); + if (map != null) { + sd = map.get(c); + } + if (sd == null) { + sd = new ServiceDispatcher(c, context, handler, flags); + if (map == null) { + map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); + mServices.put(context, map); + } + map.put(c, sd); + } else { + sd.validate(context, handler); + } + return sd.getIServiceConnection(); + } + } + + public final IServiceConnection forgetServiceDispatcher(Context context, + ServiceConnection c) { + synchronized (mServices) { + HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map + = mServices.get(context); + LoadedApk.ServiceDispatcher sd = null; + if (map != null) { + sd = map.get(c); + if (sd != null) { + map.remove(c); + sd.doForget(); + if (map.size() == 0) { + mServices.remove(context); + } + if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) { + HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder + = mUnboundServices.get(context); + if (holder == null) { + holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); + mUnboundServices.put(context, holder); + } + RuntimeException ex = new IllegalArgumentException( + "Originally unbound here:"); + ex.fillInStackTrace(); + sd.setUnbindLocation(ex); + holder.put(c, sd); + } + return sd.getIServiceConnection(); + } + } + HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder + = mUnboundServices.get(context); + if (holder != null) { + sd = holder.get(c); + if (sd != null) { + RuntimeException ex = sd.getUnbindLocation(); + throw new IllegalArgumentException( + "Unbinding Service " + c + + " that was already unbound", ex); + } + } + if (context == null) { + throw new IllegalStateException("Unbinding Service " + c + + " from Context that is no longer in use: " + context); + } else { + throw new IllegalArgumentException("Service not registered: " + c); + } + } + } + + static final class ServiceDispatcher { + private final ServiceDispatcher.InnerConnection mIServiceConnection; + private final ServiceConnection mConnection; + private final Context mContext; + private final Handler mActivityThread; + private final ServiceConnectionLeaked mLocation; + private final int mFlags; + + private RuntimeException mUnbindLocation; + + private boolean mDied; + + private static class ConnectionInfo { + IBinder binder; + IBinder.DeathRecipient deathMonitor; + } + + private static class InnerConnection extends IServiceConnection.Stub { + final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; + + InnerConnection(LoadedApk.ServiceDispatcher sd) { + mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); + } + + public void connected(ComponentName name, IBinder service) throws RemoteException { + LoadedApk.ServiceDispatcher sd = mDispatcher.get(); + if (sd != null) { + sd.connected(name, service); + } + } + } + + private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections + = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); + + ServiceDispatcher(ServiceConnection conn, + Context context, Handler activityThread, int flags) { + mIServiceConnection = new InnerConnection(this); + mConnection = conn; + mContext = context; + mActivityThread = activityThread; + mLocation = new ServiceConnectionLeaked(null); + mLocation.fillInStackTrace(); + mFlags = flags; + } + + void validate(Context context, Handler activityThread) { + if (mContext != context) { + throw new RuntimeException( + "ServiceConnection " + mConnection + + " registered with differing Context (was " + + mContext + " now " + context + ")"); + } + if (mActivityThread != activityThread) { + throw new RuntimeException( + "ServiceConnection " + mConnection + + " registered with differing handler (was " + + mActivityThread + " now " + activityThread + ")"); + } + } + + void doForget() { + synchronized(this) { + Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator(); + while (it.hasNext()) { + ServiceDispatcher.ConnectionInfo ci = it.next(); + ci.binder.unlinkToDeath(ci.deathMonitor, 0); + } + mActiveConnections.clear(); + } + } + + ServiceConnectionLeaked getLocation() { + return mLocation; + } + + ServiceConnection getServiceConnection() { + return mConnection; + } + + IServiceConnection getIServiceConnection() { + return mIServiceConnection; + } + + int getFlags() { + return mFlags; + } + + void setUnbindLocation(RuntimeException ex) { + mUnbindLocation = ex; + } + + RuntimeException getUnbindLocation() { + return mUnbindLocation; + } + + public void connected(ComponentName name, IBinder service) { + if (mActivityThread != null) { + mActivityThread.post(new RunConnection(name, service, 0)); + } else { + doConnected(name, service); + } + } + + public void death(ComponentName name, IBinder service) { + ServiceDispatcher.ConnectionInfo old; + + synchronized (this) { + mDied = true; + old = mActiveConnections.remove(name); + if (old == null || old.binder != service) { + // Death for someone different than who we last + // reported... just ignore it. + return; + } + old.binder.unlinkToDeath(old.deathMonitor, 0); + } + + if (mActivityThread != null) { + mActivityThread.post(new RunConnection(name, service, 1)); + } else { + doDeath(name, service); + } + } + + public void doConnected(ComponentName name, IBinder service) { + ServiceDispatcher.ConnectionInfo old; + ServiceDispatcher.ConnectionInfo info; + + synchronized (this) { + old = mActiveConnections.get(name); + if (old != null && old.binder == service) { + // Huh, already have this one. Oh well! + return; + } + + if (service != null) { + // A new service is being connected... set it all up. + mDied = false; + info = new ConnectionInfo(); + info.binder = service; + info.deathMonitor = new DeathMonitor(name, service); + try { + service.linkToDeath(info.deathMonitor, 0); + mActiveConnections.put(name, info); + } catch (RemoteException e) { + // This service was dead before we got it... just + // don't do anything with it. + mActiveConnections.remove(name); + return; + } + + } else { + // The named service is being disconnected... clean up. + mActiveConnections.remove(name); + } + + if (old != null) { + old.binder.unlinkToDeath(old.deathMonitor, 0); + } + } + + // If there was an old service, it is not disconnected. + if (old != null) { + mConnection.onServiceDisconnected(name); + } + // If there is a new service, it is now connected. + if (service != null) { + mConnection.onServiceConnected(name, service); + } + } + + public void doDeath(ComponentName name, IBinder service) { + mConnection.onServiceDisconnected(name); + } + + private final class RunConnection implements Runnable { + RunConnection(ComponentName name, IBinder service, int command) { + mName = name; + mService = service; + mCommand = command; + } + + public void run() { + if (mCommand == 0) { + doConnected(mName, mService); + } else if (mCommand == 1) { + doDeath(mName, mService); + } + } + + final ComponentName mName; + final IBinder mService; + final int mCommand; + } + + private final class DeathMonitor implements IBinder.DeathRecipient + { + DeathMonitor(ComponentName name, IBinder service) { + mName = name; + mService = service; + } + + public void binderDied() { + death(mName, mService); + } + + final ComponentName mName; + final IBinder mService; + } + } +} diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index b4718ab..69f7611 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -18,6 +18,7 @@ package android.content; import android.accounts.Account; import android.app.ActivityThread; +import android.app.AppGlobals; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; @@ -1306,7 +1307,7 @@ public abstract class ContentResolver { // ActivityThread.currentPackageName() only returns non-null if the // current thread is an application main thread. This parameter tells // us whether an event loop is blocked, and if so, which app it is. - String blockingPackage = ActivityThread.currentPackageName(); + String blockingPackage = AppGlobals.getInitialPackage(); EventLog.writeEvent( EventLogTags.CONTENT_QUERY_SAMPLE, @@ -1329,7 +1330,7 @@ public abstract class ContentResolver { } } } - String blockingPackage = ActivityThread.currentPackageName(); + String blockingPackage = AppGlobals.getInitialPackage(); EventLog.writeEvent( EventLogTags.CONTENT_UPDATE_SAMPLE, uri.toString(), diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 0e798dc..cdc9bbb 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -19,6 +19,7 @@ package android.database.sqlite; import com.google.android.collect.Maps; import android.app.ActivityThread; +import android.app.AppGlobals; import android.content.ContentValues; import android.database.Cursor; import android.database.DatabaseUtils; @@ -1921,7 +1922,7 @@ public class SQLiteDatabase extends SQLiteClosable { // main thread, or when we are invoked via Binder (e.g. ContentProvider). // Hopefully the full path to the database will be informative enough. - String blockingPackage = ActivityThread.currentPackageName(); + String blockingPackage = AppGlobals.getInitialPackage(); if (blockingPackage == null) blockingPackage = ""; EventLog.writeEvent( |