diff options
author | Ricardo Cerqueira <github@cerqueira.org> | 2012-05-05 18:49:09 +0100 |
---|---|---|
committer | Ricardo Cerqueira <github@cerqueira.org> | 2012-05-05 18:49:17 +0100 |
commit | e821f5b727ef247a789557badb6640880cf992dd (patch) | |
tree | fc74bf9cc07a3eac04166477bed32ee5f9583d40 /services | |
parent | f0b7008ac173a4402b982b0f50ca3db8b0659bb7 (diff) | |
parent | fd6ee4e7d2f1600021c0d2f47914c01600bd1b97 (diff) | |
download | frameworks_base-e821f5b727ef247a789557badb6640880cf992dd.zip frameworks_base-e821f5b727ef247a789557badb6640880cf992dd.tar.gz frameworks_base-e821f5b727ef247a789557badb6640880cf992dd.tar.bz2 |
Merge branch 'themes-4.0' into 'ics'
Change-Id: Idc363f8140be2d252bee2aeba46c944032fb0ae9
Diffstat (limited to 'services')
6 files changed, 687 insertions, 20 deletions
diff --git a/services/java/com/android/server/AppsLaunchFailureReceiver.java b/services/java/com/android/server/AppsLaunchFailureReceiver.java new file mode 100644 index 0000000..6ef07aa --- /dev/null +++ b/services/java/com/android/server/AppsLaunchFailureReceiver.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010, T-Mobile USA, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.CustomTheme; +import android.util.Log; +import android.app.ActivityManager; +import android.os.SystemClock; + +public class AppsLaunchFailureReceiver extends BroadcastReceiver { + + private static final int FAILURES_THRESHOLD = 5; + private static final int EXPIRATION_TIME_IN_MILLISECONDS = 30000; // 30 seconds + + private int mFailuresCount = 0; + private long mStartTime = 0; + + // This function implements the following logic. + // If after a theme was applied the number of application launch failures + // at any moment was equal to FAILURES_THRESHOLD + // in less than EXPIRATION_TIME_IN_MILLISECONDS + // the default theme is applied unconditionally. + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_APP_LAUNCH_FAILURE)) { + long currentTime = SystemClock.uptimeMillis(); + if (currentTime - mStartTime > EXPIRATION_TIME_IN_MILLISECONDS) { + // reset both the count and the timer + mStartTime = currentTime; + mFailuresCount = 0; + } + if (mFailuresCount <= FAILURES_THRESHOLD) { + mFailuresCount++; + if (mFailuresCount == FAILURES_THRESHOLD) { + CustomTheme defaultTheme = CustomTheme.getSystemTheme(); + ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); + Configuration currentConfig = am.getConfiguration(); + currentConfig.customTheme = new CustomTheme( + defaultTheme.getThemeId(), + defaultTheme.getThemePackageName()); + am.updateConfiguration(currentConfig); + } + } + } else if (action.equals(Intent.ACTION_APP_LAUNCH_FAILURE_RESET)) { + mFailuresCount = 0; + mStartTime = SystemClock.uptimeMillis(); + } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) || + action.equals(Intent.ACTION_PACKAGE_REMOVED)) { + mFailuresCount = 0; + mStartTime = SystemClock.uptimeMillis(); + } + } + +} diff --git a/services/java/com/android/server/AssetRedirectionManagerService.java b/services/java/com/android/server/AssetRedirectionManagerService.java new file mode 100644 index 0000000..1e124b9 --- /dev/null +++ b/services/java/com/android/server/AssetRedirectionManagerService.java @@ -0,0 +1,397 @@ +package com.android.server; + +import com.android.internal.app.IAssetRedirectionManager; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ThemeInfo; +import android.content.res.AssetManager; +import android.content.res.PackageRedirectionMap; +import android.content.res.Resources; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class AssetRedirectionManagerService extends IAssetRedirectionManager.Stub { + private static final String TAG = "AssetRedirectionManager"; + + private final Context mContext; + + /* + * TODO: This data structure should have some way to expire very old cache + * entries. Would be nice to optimize for the removal path as well. + */ + private final HashMap<RedirectionKey, PackageRedirectionMap> mRedirections = + new HashMap<RedirectionKey, PackageRedirectionMap>(); + + public AssetRedirectionManagerService(Context context) { + mContext = context; + } + + @Override + public void clearRedirectionMapsByTheme(String themePackageName, String themeId) + throws RemoteException { + synchronized (mRedirections) { + Set<RedirectionKey> keys = mRedirections.keySet(); + Iterator<RedirectionKey> iter = keys.iterator(); + while (iter.hasNext()) { + RedirectionKey key = iter.next(); + if (themePackageName.equals(key.themePackageName) && + (themeId == null || themeId.equals(key.themeId))) { + iter.remove(); + } + } + } + } + + @Override + public void clearPackageRedirectionMap(String targetPackageName) throws RemoteException { + synchronized (mRedirections) { + Set<RedirectionKey> keys = mRedirections.keySet(); + Iterator<RedirectionKey> iter = keys.iterator(); + while (iter.hasNext()) { + RedirectionKey key = iter.next(); + if (targetPackageName.equals(key.targetPackageName)) { + iter.remove(); + } + } + } + } + + @Override + public PackageRedirectionMap getPackageRedirectionMap(String themePackageName, + String themeId, String targetPackageName) throws RemoteException { + synchronized (mRedirections) { + RedirectionKey key = new RedirectionKey(); + key.themePackageName = themePackageName; + key.themeId = themeId; + key.targetPackageName = targetPackageName; + + PackageRedirectionMap map = mRedirections.get(key); + if (map != null) { + return map; + } else { + map = generatePackageRedirectionMap(key); + if (map != null) { + mRedirections.put(key, map); + } + return map; + } + } + } + + private PackageRedirectionMap generatePackageRedirectionMap(RedirectionKey key) { + AssetManager assets = new AssetManager(); + + boolean frameworkAssets = key.targetPackageName.equals("android"); + + if (!frameworkAssets) { + PackageInfo pi = getPackageInfo(mContext, key.targetPackageName); + if (pi == null || pi.applicationInfo == null || + assets.addAssetPath(pi.applicationInfo.publicSourceDir) == 0) { + Log.w(TAG, "Unable to attach target package assets for " + key.targetPackageName); + return null; + } + } + + PackageInfo pi = getPackageInfo(mContext, key.themePackageName); + if (pi == null || pi.applicationInfo == null || pi.themeInfos == null || + assets.addAssetPath(pi.applicationInfo.publicSourceDir) == 0) { + Log.w(TAG, "Unable to attach theme package assets from " + key.themePackageName); + return null; + } + + PackageRedirectionMap resMap = new PackageRedirectionMap(); + + /* + * Apply a special redirection hack for the highest level <style> + * replacing @android:style/Theme. + */ + if (frameworkAssets) { + int themeResourceId = findThemeResourceId(pi.themeInfos, key.themeId); + assets.generateStyleRedirections(resMap.getNativePointer(), android.R.style.Theme, + themeResourceId); + } + + Resources res = new Resources(assets, null, null); + generateExplicitRedirections(resMap, res, key.themePackageName, key.targetPackageName); + + return resMap; + } + + private void generateExplicitRedirections(PackageRedirectionMap resMap, Resources res, + String themePackageName, String targetPackageName) { + /* + * XXX: We should be parsing the <theme> tag's <meta-data>! Instead, + * we're just assuming that res/xml/<package>.xml exists and describes + * the redirects we want! + */ + String redirectXmlName = targetPackageName.replace('.', '_'); + int redirectXmlResId = res.getIdentifier(redirectXmlName, "xml", themePackageName); + if (redirectXmlResId == 0) { + return; + } + + ResourceRedirectionsProcessor processor = new ResourceRedirectionsProcessor(res, + redirectXmlResId, themePackageName, targetPackageName, resMap); + processor.process(); + } + + private static PackageInfo getPackageInfo(Context context, String packageName) { + try { + return context.getPackageManager().getPackageInfo(packageName, 0); + } catch (NameNotFoundException e) { + return null; + } + } + + /** + * Searches for the high-level theme resource id for the specific + * <theme> tag being applied. + * <p> + * An individual theme package can contain multiple <theme> tags, each + * representing a separate theme choice from the user's perspective, even + * though the most common case is for there to be only 1. + * + * @return The style resource id or 0 if no match was found. + */ + private static int findThemeResourceId(ThemeInfo[] themeInfos, String needle) { + if (themeInfos != null && !TextUtils.isEmpty(needle)) { + int n = themeInfos.length; + for (int i = 0; i < n; i++) { + ThemeInfo info = themeInfos[i]; + if (needle.equals(info.themeId)) { + return info.styleResourceId; + } + } + } + return 0; + } + + private static Resources getUnredirectedResourcesForPackage(Context context, String packageName) { + AssetManager assets = new AssetManager(); + + if (!packageName.equals("android")) { + PackageInfo pi = getPackageInfo(context, packageName); + if (pi == null || pi.applicationInfo == null || + assets.addAssetPath(pi.applicationInfo.publicSourceDir) == 0) { + Log.w(TAG, "Unable to get resources for package " + packageName); + return null; + } + } + + return new Resources(assets, null, null); + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + synchronized (mRedirections) { + final ArrayList<RedirectionKey> filteredKeySet = new ArrayList<RedirectionKey>(); + for (Map.Entry<RedirectionKey, PackageRedirectionMap> entry: mRedirections.entrySet()) { + PackageRedirectionMap map = entry.getValue(); + if (map != null && map.getPackageId() != -1) { + filteredKeySet.add(entry.getKey()); + } + } + Collections.sort(filteredKeySet, new Comparator<RedirectionKey>() { + @Override + public int compare(RedirectionKey a, RedirectionKey b) { + int comp = a.themePackageName.compareTo(b.themePackageName); + if (comp != 0) { + return comp; + } + comp = a.themeId.compareTo(b.themeId); + if (comp != 0) { + return comp; + } + return a.targetPackageName.compareTo(b.targetPackageName); + } + }); + + pw.println("Theme asset redirections:"); + String lastPackageName = null; + String lastId = null; + Resources themeRes = null; + for (RedirectionKey key: filteredKeySet) { + if (lastPackageName == null || !lastPackageName.equals(key.themePackageName)) { + pw.println("* Theme package " + key.themePackageName + ":"); + lastPackageName = key.themePackageName; + themeRes = getUnredirectedResourcesForPackage(mContext, key.themePackageName); + } + if (lastId == null || !lastId.equals(key.themeId)) { + pw.println(" theme id #" + key.themeId + ":"); + lastId = key.themeId; + } + pw.println(" " + key.targetPackageName + ":"); + Resources targetRes = getUnredirectedResourcesForPackage(mContext, key.targetPackageName); + PackageRedirectionMap resMap = mRedirections.get(key); + int[] fromIdents = resMap.getRedirectionKeys(); + int N = fromIdents.length; + for (int i = 0; i < N; i++) { + int fromIdent = fromIdents[i]; + int toIdent = resMap.lookupRedirection(fromIdent); + String fromName = targetRes != null ? targetRes.getResourceName(fromIdent) : null; + String toName = themeRes != null ? themeRes.getResourceName(toIdent) : null; + pw.println(String.format(" %s (0x%08x) => %s (0x%08x)", fromName, fromIdent, + toName, toIdent)); + } + } + } + } + + private static class RedirectionKey { + public String themePackageName; + public String themeId; + public String targetPackageName; + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof RedirectionKey)) return false; + final RedirectionKey oo = (RedirectionKey)o; + if (!nullSafeEquals(themePackageName, oo.themePackageName)) { + return false; + } + if (!nullSafeEquals(themeId, oo.themeId)) { + return false; + } + if (!nullSafeEquals(targetPackageName, oo.targetPackageName)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return themePackageName.hashCode() + + themeId.hashCode() + + targetPackageName.hashCode(); + } + + private static boolean nullSafeEquals(Object a, Object b) { + if (a == null) { + return b == a; + } else if (b == null) { + return false; + } else { + return a.equals(b); + } + } + } + + /** + * Parses and processes explicit redirection XML files. + */ + private static class ResourceRedirectionsProcessor { + private final Resources mResources; + private final XmlPullParser mParser; + private final int mResourceId; + private final String mThemePackageName; + private final String mTargetPackageName; + private final PackageRedirectionMap mResMap; + + public ResourceRedirectionsProcessor(Resources res, int resourceId, + String themePackageName, String targetPackageName, + PackageRedirectionMap outMap) { + mResources = res; + mParser = res.getXml(resourceId); + mResourceId = resourceId; + mThemePackageName = themePackageName; + mTargetPackageName = targetPackageName; + mResMap = outMap; + } + + public void process() { + XmlPullParser parser = mParser; + int type; + try { + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + // just loop... + } + + String tagName = parser.getName(); + if (parser.getName().equals("resource-redirections")) { + processResourceRedirectionsTag(); + } else { + Log.w(TAG, "Unknown root element: " + tagName + " at " + getResourceLabel() + " " + + parser.getPositionDescription()); + } + } catch (XmlPullParserException e) { + Log.w(TAG, "Malformed theme redirection meta at " + getResourceLabel()); + } catch (IOException e) { + Log.w(TAG, "Unknown error reading redirection meta at " + getResourceLabel()); + } + } + + private void processResourceRedirectionsTag() throws XmlPullParserException, IOException { + XmlPullParser parser = mParser; + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && + (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("item")) { + processItemTag(); + } else { + Log.w(TAG, "Unknown element under <resource-redirections>: " + tagName + + " at " + getResourceLabel() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + } + } + + private void processItemTag() throws XmlPullParserException, IOException { + XmlPullParser parser = mParser; + String fromName = parser.getAttributeValue(null, "name"); + if (TextUtils.isEmpty(fromName)) { + Log.w(TAG, "Missing android:name attribute on <item> tag at " + getResourceLabel() + " " + + parser.getPositionDescription()); + return; + } + String toName = parser.nextText(); + if (TextUtils.isEmpty(toName)) { + Log.w(TAG, "Missing <item> text at " + getResourceLabel() + " " + + parser.getPositionDescription()); + return; + } + int fromIdent = mResources.getIdentifier(fromName, null, mTargetPackageName); + if (fromIdent == 0) { + Log.w(TAG, "No such resource found for " + mTargetPackageName + ":" + fromName); + return; + } + int toIdent = mResources.getIdentifier(toName, null, mThemePackageName); + if (toIdent == 0) { + Log.w(TAG, "No such resource found for " + mThemePackageName + ":" + toName); + return; + } + mResMap.addRedirection(fromIdent, toIdent); + } + + private String getResourceLabel() { + return "resource #0x" + Integer.toHexString(mResourceId); + } + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index d8ea9bf..ad78a3c 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 The Android Open Source Project * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +26,7 @@ import android.content.ContentResolver; import android.content.ContentService; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.res.Configuration; import android.database.ContentObserver; @@ -601,6 +603,13 @@ class ServerThread extends Thread { } catch (Throwable e) { reportWtf("starting NetworkTimeUpdate service", e); } + + try { + Slog.i(TAG, "AssetRedirectionManager Service"); + ServiceManager.addService("assetredirection", new AssetRedirectionManagerService(context)); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting AssetRedirectionManager Service", e); + } } // make sure the ADB_ENABLED setting value matches the secure property value @@ -670,6 +679,15 @@ class ServerThread extends Thread { reportWtf("making Package Manager Service ready", e); } + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_APP_LAUNCH_FAILURE); + filter.addAction(Intent.ACTION_APP_LAUNCH_FAILURE_RESET); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addCategory(Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE); + filter.addDataScheme("package"); + context.registerReceiver(new AppsLaunchFailureReceiver(), filter); + // These are needed to propagate to the runnable below. final Context contextF = context; final BatteryService batteryF = battery; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index cffb391..2d06e8c 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006-2008 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,6 +79,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.content.res.CustomTheme; import android.graphics.Bitmap; import android.net.Proxy; import android.net.ProxyProperties; @@ -147,6 +149,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import dalvik.system.Zygote; public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { @@ -13462,6 +13465,11 @@ public final class ActivityManagerService extends ActivityManagerNative values.userSetLocale); } + if (values.customTheme != null) { + saveThemeResourceLocked(values.customTheme, + !values.customTheme.equals(mConfiguration.customTheme)); + } + mConfigurationSeq++; if (mConfigurationSeq <= 0) { mConfigurationSeq = 1; @@ -13554,6 +13562,13 @@ public final class ActivityManagerService extends ActivityManagerNative } } + private void saveThemeResourceLocked(CustomTheme t, boolean isDiff){ + if(isDiff){ + SystemProperties.set(Configuration.THEME_ID_PERSISTENCE_PROPERTY, t.getThemeId()); + SystemProperties.set(Configuration.THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY, t.getThemePackageName()); + } + } + // ========================================================= // LIFETIME MANAGEMENT // ========================================================= diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 0eeb377..8719e8e 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +23,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import static libcore.io.OsConstants.S_ISLNK; +import com.android.internal.app.IAssetRedirectionManager; import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; import com.android.internal.content.NativeLibraryHelper; @@ -183,6 +185,8 @@ public class PackageManagerService extends IPackageManager.Stub { // package apks to install directory. private static final String INSTALL_PACKAGE_SUFFIX = "-"; + private static final int THEME_MAMANER_GUID = 1300; + static final int SCAN_MONITOR = 1<<0; static final int SCAN_NO_DEX = 1<<1; static final int SCAN_FORCE_DEX = 1<<2; @@ -374,6 +378,8 @@ public class PackageManagerService extends IPackageManager.Stub { ComponentName mResolveComponentName; PackageParser.Package mPlatformPackage; + IAssetRedirectionManager mAssetRedirectionManager; + // Set of pending broadcasts for aggregating enable/disable of components. final HashMap<String, ArrayList<String>> mPendingBroadcasts = new HashMap<String, ArrayList<String>>(); @@ -663,22 +669,26 @@ public class PackageManagerService extends IPackageManager.Stub { PackageInstalledInfo res = data.res; if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - res.removedInfo.sendBroadcast(false, true); + res.removedInfo.sendBroadcast(false, true, false); Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, res.uid); final boolean update = res.removedInfo.removedPackage != null; if (update) { extras.putBoolean(Intent.EXTRA_REPLACING, true); } + String category = null; + if(res.pkg.mIsThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, - res.pkg.applicationInfo.packageName, + res.pkg.applicationInfo.packageName, category, extras, null, null); if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, - res.pkg.applicationInfo.packageName, + res.pkg.applicationInfo.packageName, category, extras, null, null); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, - null, null, + null, null, null, res.pkg.applicationInfo.packageName, null); } if (res.removedInfo.args != null) { @@ -881,6 +891,9 @@ public class PackageManagerService extends IPackageManager.Stub { MULTIPLE_APPLICATION_UIDS ? LOG_UID : FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); + mSettings.addSharedUserLPw("com.tmobile.thememanager", + THEME_MAMANER_GUID, + ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.nfc", MULTIPLE_APPLICATION_UIDS ? NFC_UID : FIRST_APPLICATION_UID, @@ -2586,6 +2599,20 @@ public class PackageManagerService extends IPackageManager.Stub { return list; } + public List<PackageInfo> getInstalledThemePackages() { + // Returns a list of theme APKs. + ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>(); + List<PackageInfo> installedPackagesList = mContext.getPackageManager().getInstalledPackages(0); + Iterator<PackageInfo> i = installedPackagesList.iterator(); + while (i.hasNext()) { + final PackageInfo pi = i.next(); + if (pi != null && pi.isThemeApk) { + finalList.add(pi); + } + } + return finalList; + } + public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, String lastRead) { final ParceledListSlice<ApplicationInfo> list = new ParceledListSlice<ApplicationInfo>(); @@ -3952,6 +3979,32 @@ public class PackageManagerService extends IPackageManager.Stub { } } + // NOTE: this method can return null if the SystemServer is still + // initializing + public IAssetRedirectionManager getAssetRedirectionManager() { + if (mAssetRedirectionManager != null) { + return mAssetRedirectionManager; + } + IBinder b = ServiceManager.getService("assetredirection"); + mAssetRedirectionManager = IAssetRedirectionManager.Stub.asInterface(b); + return mAssetRedirectionManager; + } + + private void cleanAssetRedirections(PackageParser.Package pkg) { + IAssetRedirectionManager rm = getAssetRedirectionManager(); + if (rm == null) { + return; + } + try { + if (pkg.mIsThemeApk) { + rm.clearRedirectionMapsByTheme(pkg.packageName, null); + } else { + rm.clearPackageRedirectionMap(pkg.packageName); + } + } catch (RemoteException e) { + } + } + void removePackageLI(PackageParser.Package pkg, boolean chatty) { if (DEBUG_INSTALL) { if (chatty) @@ -3960,6 +4013,8 @@ public class PackageManagerService extends IPackageManager.Stub { // writer synchronized (mPackages) { + cleanAssetRedirections(pkg); + clearPackagePreferredActivitiesLPw(pkg.packageName); mPackages.remove(pkg.applicationInfo.packageName); @@ -4742,7 +4797,7 @@ public class PackageManagerService extends IPackageManager.Stub { } }; - static final void sendPackageBroadcast(String action, String pkg, + static final void sendPackageBroadcast(String action, String pkg, String intentCategory, Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { @@ -4756,6 +4811,9 @@ public class PackageManagerService extends IPackageManager.Stub { intent.setPackage(targetPkg); } intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + if (intentCategory != null) { + intent.addCategory(intentCategory); + } am.broadcastIntent(null, intent, null, finishedReceiver, 0, null, null, null, finishedReceiver != null, false); } catch (RemoteException ex) { @@ -4826,6 +4884,7 @@ public class PackageManagerService extends IPackageManager.Stub { int removedUid = -1; String addedPackage = null; int addedUid = -1; + String category = null; // TODO post a message to the handler to obtain serial ordering synchronized (mInstallLock) { @@ -4857,6 +4916,9 @@ public class PackageManagerService extends IPackageManager.Stub { } if ((event&REMOVE_EVENTS) != 0) { if (p != null) { + if (p.mIsThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } removePackageLI(p, true); removedPackage = p.applicationInfo.packageName; removedUid = p.applicationInfo.uid; @@ -4887,6 +4949,9 @@ public class PackageManagerService extends IPackageManager.Stub { addedUid = p.applicationInfo.uid; } } + if (p != null && p.mIsThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } } // reader @@ -4899,13 +4964,13 @@ public class PackageManagerService extends IPackageManager.Stub { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedUid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); - sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, + sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, category, extras, null, null); } if (addedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, addedUid); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, + sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, category, extras, null, null); } } @@ -6591,6 +6656,23 @@ public class PackageManagerService extends IPackageManager.Stub { } else { Log.d(TAG, "New package installed in " + newPackage.mPath); } + cleanAssetRedirections(newPackage); + + if (newPackage.mIsThemeApk) { + /* DBS-TODO + boolean isThemePackageDrmProtected = false; + int N = newPackage.mThemeInfos.size(); + for (int i = 0; i < N; i++) { + if (newPackage.mThemeInfos.get(i).isDrmProtected) { + isThemePackageDrmProtected = true; + break; + } + } + if (isThemePackageDrmProtected) { + splitThemePackage(newPackage.mPath); + } + */ + } synchronized (mPackages) { updatePermissionsLPw(newPackage.packageName, newPackage, newPackage.permissions.size() > 0, true, false); @@ -6605,6 +6687,66 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private void deleteLockedZipFileIfExists(String originalPackagePath) { + String lockedZipFilePath = PackageParser.getLockedZipFilePath(originalPackagePath); + File zipFile = new File(lockedZipFilePath); + if (zipFile.exists() && zipFile.isFile()) { + if (!zipFile.delete()) { + Log.w(TAG, "Couldn't delete locked zip file: " + originalPackagePath); + } + } + } + + private void splitThemePackage(File originalFile) { + final String originalPackagePath = originalFile.getPath(); + final String lockedZipFilePath = PackageParser.getLockedZipFilePath(originalPackagePath); + + try { + final List<String> drmProtectedEntries = new ArrayList<String>(); + final ZipFile privateZip = new ZipFile(originalFile.getPath()); + + final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries(); + while (privateZipEntries.hasMoreElements()) { + final ZipEntry zipEntry = privateZipEntries.nextElement(); + final String zipEntryName = zipEntry.getName(); + if (zipEntryName.startsWith("assets/") && zipEntryName.contains("/locked/")) { + drmProtectedEntries.add(zipEntryName); + } + } + privateZip.close(); + + String [] args = new String[0]; + args = drmProtectedEntries.toArray(args); + int code = mContext.getAssets().splitDrmProtectedThemePackage( + originalPackagePath, + lockedZipFilePath, + args); + if (code != 0) { + Log.e("PackageManagerService", + "splitDrmProtectedThemePackage returned = " + code); + } + code = FileUtils.setPermissions( + lockedZipFilePath, + 0640, + -1, + THEME_MAMANER_GUID); + if (code != 0) { + Log.e("PackageManagerService", + "Set permissions for " + lockedZipFilePath + " returned = " + code); + } + code = FileUtils.setPermissions( + originalPackagePath, + 0644, + -1, -1); + if (code != 0) { + Log.e("PackageManagerService", + "Set permissions for " + originalPackagePath + " returned = " + code); + } + } catch (IOException e) { + Log.e(TAG, "Failure to generate new zip files for theme"); + } + } + private void installPackageLI(InstallArgs args, boolean newInstall, PackageInstalledInfo res) { int pFlags = args.flags; @@ -6915,7 +7057,18 @@ public class PackageManagerService extends IPackageManager.Stub { } } catch (RemoteException e) { } - + + synchronized (mPackages) { + PackageParser.Package p = mPackages.get(packageName); + if (p != null) { + info.isThemeApk = p.mIsThemeApk; + if (info.isThemeApk && deleteCodeAndResources && + !info.isRemovedPackageSystemUpdate && sendBroadCast) { + deleteLockedZipFileIfExists(p.mPath); + } + } + } + synchronized (mInstallLock) { res = deletePackageLI(packageName, deleteCodeAndResources, flags | REMOVE_CHATTY, info, true); @@ -6923,7 +7076,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (res && sendBroadCast) { boolean systemUpdate = info.isRemovedPackageSystemUpdate; - info.sendBroadcast(deleteCodeAndResources, systemUpdate); + info.sendBroadcast(deleteCodeAndResources, systemUpdate, true); // If the removed package was a system update, the old system packaged // was re-enabled; we need to broadcast this information @@ -6932,11 +7085,16 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid); extras.putBoolean(Intent.EXTRA_REPLACING, true); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, + String category = null; + if (info.isThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } + + sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, category, extras, null, null); - sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, + sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, category, extras, null, null); - sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, + sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, null, packageName, null); } } @@ -6960,8 +7118,10 @@ public class PackageManagerService extends IPackageManager.Stub { boolean isRemovedPackageSystemUpdate = false; // Clean up resources deleted packages. InstallArgs args = null; + boolean isThemeApk = false; - void sendBroadcast(boolean fullRemove, boolean replacing) { + void sendBroadcast(boolean fullRemove, boolean replacing, + boolean deleteLockedZipFileIfExists) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove); @@ -6969,15 +7129,19 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putBoolean(Intent.EXTRA_REPLACING, true); } if (removedPackage != null) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, + String category = null; + if (isThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } + sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, category, extras, null, null); if (fullRemove && !replacing) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, + sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, category, extras, null, null); } } if (removedUid >= 0) { - sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null); + sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, null, extras, null, null); } } } @@ -7684,7 +7848,7 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag); extras.putInt(Intent.EXTRA_UID, packageUid); - sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null); + sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, null, extras, null, null); } public void setPackageStoppedState(String packageName, boolean stopped) { @@ -8240,7 +8404,7 @@ public class PackageManagerService extends IPackageManager.Stub { } String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; - sendPackageBroadcast(action, null, extras, null, finishedReceiver); + sendPackageBroadcast(action, null, null, extras, null, finishedReceiver); } } diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 36442a0..46f10d2 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -2010,7 +2010,7 @@ final class Settings { if (pkgSetting.notLaunched) { if (pkgSetting.installerPackageName != null) { PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, - pkgSetting.name, null, + pkgSetting.name, null, null, pkgSetting.installerPackageName, null); } pkgSetting.notLaunched = false; @@ -2261,4 +2261,4 @@ final class Settings { pw.println("Settings parse messages:"); pw.print(mReadMessages.toString()); } -}
\ No newline at end of file +} |