summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-05-27 16:45:31 -0700
committerDianne Hackborn <hackbod@google.com>2011-05-27 16:49:29 -0700
commit8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d (patch)
treea676c6b0daf45a90b600d3268bb37e81f23a2275
parentb96cbbd11c4590bec846212c33361e02293f18b5 (diff)
downloadframeworks_base-8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d.zip
frameworks_base-8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d.tar.gz
frameworks_base-8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d.tar.bz2
Fix compat mode bugs when updating apps.
No longer accidentally puts an app into compatibility mode. Also various cleanup, freezing screen while switching between modes. Change-Id: Ic1b3958be7800189a93f68e9dee3c5adfc45fe57
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java118
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java16
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java3
-rw-r--r--services/java/com/android/server/am/ActivityStack.java4
-rw-r--r--services/java/com/android/server/am/CompatModePackages.java83
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java2
6 files changed, 141 insertions, 85 deletions
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index c151e32..e42caca 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -63,37 +63,19 @@ public class CompatibilityInfo implements Parcelable {
private static final int SCALING_REQUIRED = 1;
/**
- * Has the application said that its UI is expandable? Based on the
- * <supports-screen> android:expandible in the manifest.
- */
- private static final int EXPANDABLE = 2;
-
- /**
- * Has the application said that its UI supports large screens? Based on the
- * <supports-screen> android:largeScreens in the manifest.
- */
- private static final int LARGE_SCREENS = 8;
-
- /**
- * Has the application said that its UI supports xlarge screens? Based on the
- * <supports-screen> android:xlargeScreens in the manifest.
- */
- private static final int XLARGE_SCREENS = 32;
-
- /**
* Application must always run in compatibility mode?
*/
- private static final int ALWAYS_COMPAT = 64;
+ private static final int ALWAYS_NEEDS_COMPAT = 2;
/**
* Application never should run in compatibility mode?
*/
- private static final int NEVER_COMPAT = 128;
+ private static final int NEVER_NEEDS_COMPAT = 4;
/**
* Set if the application needs to run in screen size compatibility mode.
*/
- private static final int NEEDS_SCREEN_COMPAT = 256;
+ private static final int NEEDS_SCREEN_COMPAT = 8;
/**
* The effective screen density we have selected for this application.
@@ -127,7 +109,7 @@ public class CompatibilityInfo implements Parcelable {
}
if (compat >= sw) {
- compatFlags |= NEVER_COMPAT;
+ compatFlags |= NEVER_NEEDS_COMPAT;
} else if (forceCompat) {
compatFlags |= NEEDS_SCREEN_COMPAT;
}
@@ -138,29 +120,49 @@ public class CompatibilityInfo implements Parcelable {
applicationInvertedScale = 1.0f;
} else {
+ /**
+ * Has the application said that its UI is expandable? Based on the
+ * <supports-screen> android:expandible in the manifest.
+ */
+ final int EXPANDABLE = 2;
+
+ /**
+ * Has the application said that its UI supports large screens? Based on the
+ * <supports-screen> android:largeScreens in the manifest.
+ */
+ final int LARGE_SCREENS = 8;
+
+ /**
+ * Has the application said that its UI supports xlarge screens? Based on the
+ * <supports-screen> android:xlargeScreens in the manifest.
+ */
+ final int XLARGE_SCREENS = 32;
+
+ int sizeInfo = 0;
+
// We can't rely on the application always setting
// FLAG_RESIZEABLE_FOR_SCREENS so will compute it based on various input.
boolean anyResizeable = false;
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
- compatFlags |= LARGE_SCREENS;
+ sizeInfo |= LARGE_SCREENS;
anyResizeable = true;
if (!forceCompat) {
// If we aren't forcing the app into compatibility mode, then
// assume if it supports large screens that we should allow it
// to use the full space of an xlarge screen as well.
- compatFlags |= XLARGE_SCREENS | EXPANDABLE;
+ sizeInfo |= XLARGE_SCREENS | EXPANDABLE;
}
}
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
anyResizeable = true;
if (!forceCompat) {
- compatFlags |= XLARGE_SCREENS | EXPANDABLE;
+ sizeInfo |= XLARGE_SCREENS | EXPANDABLE;
}
}
if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
anyResizeable = true;
- compatFlags |= EXPANDABLE;
+ sizeInfo |= EXPANDABLE;
}
if (forceCompat) {
@@ -168,43 +170,37 @@ public class CompatibilityInfo implements Parcelable {
// just says it is resizable for screens. We'll only have it fill
// the screen if it explicitly says it supports the screen size we
// are running in.
- compatFlags &= ~EXPANDABLE;
+ sizeInfo &= ~EXPANDABLE;
}
- boolean supportsScreen = false;
+ compatFlags |= NEEDS_SCREEN_COMPAT;
switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) {
case Configuration.SCREENLAYOUT_SIZE_XLARGE:
- if ((compatFlags&XLARGE_SCREENS) != 0) {
- supportsScreen = true;
+ if ((sizeInfo&XLARGE_SCREENS) != 0) {
+ compatFlags &= ~NEEDS_SCREEN_COMPAT;
}
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
- compatFlags |= NEVER_COMPAT;
+ compatFlags |= NEVER_NEEDS_COMPAT;
}
break;
case Configuration.SCREENLAYOUT_SIZE_LARGE:
- if ((compatFlags&LARGE_SCREENS) != 0) {
- supportsScreen = true;
+ if ((sizeInfo&LARGE_SCREENS) != 0) {
+ compatFlags &= ~NEEDS_SCREEN_COMPAT;
}
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
- compatFlags |= NEVER_COMPAT;
+ compatFlags |= NEVER_NEEDS_COMPAT;
}
break;
}
if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) != 0) {
- if ((compatFlags&EXPANDABLE) != 0) {
- supportsScreen = true;
+ if ((sizeInfo&EXPANDABLE) != 0) {
+ compatFlags &= ~NEEDS_SCREEN_COMPAT;
} else if (!anyResizeable) {
- compatFlags |= ALWAYS_COMPAT;
+ compatFlags |= ALWAYS_NEEDS_COMPAT;
}
}
- if (supportsScreen) {
- compatFlags &= ~NEEDS_SCREEN_COMPAT;
- } else {
- compatFlags |= NEEDS_SCREEN_COMPAT;
- }
-
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
applicationDensity = DisplayMetrics.DENSITY_DEVICE;
applicationScale = 1.0f;
@@ -230,8 +226,7 @@ public class CompatibilityInfo implements Parcelable {
}
private CompatibilityInfo() {
- this(XLARGE_SCREENS | LARGE_SCREENS | EXPANDABLE,
- DisplayMetrics.DENSITY_DEVICE,
+ this(NEVER_NEEDS_COMPAT, DisplayMetrics.DENSITY_DEVICE,
1.0f,
1.0f);
}
@@ -240,7 +235,7 @@ public class CompatibilityInfo implements Parcelable {
* @return true if the scaling is required
*/
public boolean isScalingRequired() {
- return (mCompatibilityFlags & SCALING_REQUIRED) != 0;
+ return (mCompatibilityFlags&SCALING_REQUIRED) != 0;
}
public boolean supportsScreen() {
@@ -248,16 +243,11 @@ public class CompatibilityInfo implements Parcelable {
}
public boolean neverSupportsScreen() {
- return (mCompatibilityFlags&NEVER_COMPAT) != 0;
+ return (mCompatibilityFlags&NEVER_NEEDS_COMPAT) != 0;
}
public boolean alwaysSupportsScreen() {
- return (mCompatibilityFlags&ALWAYS_COMPAT) != 0;
- }
-
- @Override
- public String toString() {
- return "CompatibilityInfo{scale=" + applicationScale + "}";
+ return (mCompatibilityFlags&ALWAYS_NEEDS_COMPAT) != 0;
}
/**
@@ -516,6 +506,28 @@ public class CompatibilityInfo implements Parcelable {
}
@Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("{");
+ sb.append(applicationDensity);
+ sb.append("dpi");
+ if (isScalingRequired()) {
+ sb.append(" scaling");
+ }
+ if (!supportsScreen()) {
+ sb.append(" resizing");
+ }
+ if (neverSupportsScreen()) {
+ sb.append(" never-compat");
+ }
+ if (alwaysSupportsScreen()) {
+ sb.append(" always-compat");
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ @Override
public int hashCode() {
int result = 17;
result = 31 * result + mCompatibilityFlags;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 65b3258..080cbda 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3642,12 +3642,12 @@ public final class ActivityManagerService extends ActivityManagerNative
+ processName + " with config " + mConfiguration);
ApplicationInfo appInfo = app.instrumentationInfo != null
? app.instrumentationInfo : app.info;
+ app.compat = compatibilityInfoForPackageLocked(appInfo);
thread.bindApplication(processName, appInfo, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode,
- mConfiguration, compatibilityInfoForPackageLocked(appInfo),
- getCommonServicesLocked(),
+ mConfiguration, app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, true);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
@@ -10977,13 +10977,11 @@ public final class ActivityManagerService extends ActivityManagerNative
// Special case for adding a package: by default turn on compatibility
// mode.
} else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
- if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- Uri data = intent.getData();
- String ssp;
- if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
- mCompatModePackages.setPackageScreenCompatModeLocked(ssp,
- ActivityManager.COMPAT_MODE_ENABLED);
- }
+ Uri data = intent.getData();
+ String ssp;
+ if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
+ mCompatModePackages.handlePackageAddedLocked(ssp,
+ intent.getBooleanExtra(Intent.EXTRA_REPLACING, false));
}
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index d27cbda..33c12f4 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -24,6 +24,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.os.Build;
@@ -78,6 +79,7 @@ class ActivityRecord extends IApplicationToken.Stub {
long startTime; // last time this activity was started
long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
Configuration configuration; // configuration activity was last running in
+ CompatibilityInfo compat;// last used compatibility mode
ActivityRecord resultTo; // who started this entry, so will get our reply
final String resultWho; // additional identifier for use by resultTo.
final int requestCode; // code given by requester (resultTo)
@@ -137,6 +139,7 @@ class ActivityRecord extends IApplicationToken.Stub {
pw.print(" componentSpecified="); pw.print(componentSpecified);
pw.print(" isHomeActivity="); pw.println(isHomeActivity);
pw.print(prefix); pw.print("config="); pw.println(configuration);
+ pw.print(prefix); pw.print("compat="); pw.println(compat);
if (resultTo != null || resultWho != null) {
pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
pw.print(" resultWho="); pw.print(resultWho);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a704f88..65ea4f4 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -546,10 +546,10 @@ public class ActivityStack {
r.sleeping = false;
r.forceNewConfig = false;
showAskCompatModeDialogLocked(r);
+ r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
- r.info, mService.compatibilityInfoForPackageLocked(r.info.applicationInfo),
- r.icicle, results, newIntents, !andResume,
+ r.info, r.compat, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward());
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index 221b59b..8949f48 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -17,6 +17,7 @@ import com.android.internal.util.FastXmlSerializer;
import android.app.ActivityManager;
import android.app.AppGlobals;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.res.CompatibilityInfo;
@@ -117,6 +118,37 @@ public class CompatModePackages {
return flags != null ? flags : 0;
}
+ public void handlePackageAddedLocked(String packageName, boolean updated) {
+ ApplicationInfo ai = null;
+ try {
+ ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0);
+ } catch (RemoteException e) {
+ }
+ if (ai == null) {
+ return;
+ }
+ CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai);
+ final boolean mayCompat = !ci.alwaysSupportsScreen()
+ && !ci.neverSupportsScreen();
+
+ if (!updated) {
+ // First time -- if the app may run in compat mode, enable that
+ // by default.
+ if (mayCompat) {
+ setPackageScreenCompatModeLocked(ai, ActivityManager.COMPAT_MODE_ENABLED);
+ }
+ } else {
+ // Update -- if the app no longer can run in compat mode, clear
+ // any current settings for it.
+ if (!mayCompat && mPackages.containsKey(packageName)) {
+ mPackages.remove(packageName);
+ mHandler.removeMessages(MSG_WRITE);
+ Message msg = mHandler.obtainMessage(MSG_WRITE);
+ mHandler.sendMessageDelayed(msg, 10000);
+ }
+ }
+ }
+
public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
return new CompatibilityInfo(ai, mService.mConfiguration.screenLayout,
mService.mConfiguration.smallestScreenWidthDp,
@@ -242,28 +274,47 @@ public class CompatModePackages {
newFlags &= ~COMPAT_FLAG_ENABLED;
}
+ CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai);
+ if (ci.alwaysSupportsScreen()) {
+ Slog.w(TAG, "Ignoring compat mode change of " + packageName
+ + "; compatibility never needed");
+ newFlags = 0;
+ }
+ if (ci.neverSupportsScreen()) {
+ Slog.w(TAG, "Ignoring compat mode change of " + packageName
+ + "; compatibility always needed");
+ newFlags = 0;
+ }
+
if (newFlags != curFlags) {
if (newFlags != 0) {
mPackages.put(packageName, newFlags);
} else {
mPackages.remove(packageName);
}
- CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai);
- if (ci.alwaysSupportsScreen()) {
- Slog.w(TAG, "Ignoring compat mode change of " + packageName
- + "; compatibility never needed");
- return;
- }
- if (ci.neverSupportsScreen()) {
- Slog.w(TAG, "Ignoring compat mode change of " + packageName
- + "; compatibility always needed");
- return;
- }
+
+ // Need to get compatibility info in new state.
+ ci = compatibilityInfoForPackageLocked(ai);
mHandler.removeMessages(MSG_WRITE);
Message msg = mHandler.obtainMessage(MSG_WRITE);
mHandler.sendMessageDelayed(msg, 10000);
+ ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null);
+
+ // All activities that came from the package must be
+ // restarted as if there was a config change.
+ for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) {
+ ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i);
+ if (a.info.packageName.equals(packageName)) {
+ a.forceNewConfig = true;
+ if (starting != null && a == starting && a.visible) {
+ a.startFreezingScreenLocked(starting.app,
+ ActivityInfo.CONFIG_SCREEN_LAYOUT);
+ }
+ }
+ }
+
// Tell all processes that loaded this package about the change.
for (int i=mService.mLruProcesses.size()-1; i>=0; i--) {
ProcessRecord app = mService.mLruProcesses.get(i);
@@ -280,16 +331,6 @@ public class CompatModePackages {
}
}
- // All activities that came from the packge must be
- // restarted as if there was a config change.
- for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) {
- ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i);
- if (a.info.packageName.equals(packageName)) {
- a.forceNewConfig = true;
- }
- }
-
- ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null);
if (starting != null) {
mService.mMainStack.ensureActivityConfigurationLocked(starting, 0);
// And we need to make sure at this point that all other activities
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index a63ffae..5465e37 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -69,6 +69,7 @@ class ProcessRecord {
IBinder forcingToForeground;// Token that is forcing this process to be foreground
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
int lruSeq; // Sequence id for identifying LRU update cycles
+ CompatibilityInfo compat; // last used compatibility mode
ComponentName instrumentationClass;// class installed to instrument app
ApplicationInfo instrumentationInfo; // the application being instrumented
String instrumentationProfileFile; // where to save profiling
@@ -145,6 +146,7 @@ class ProcessRecord {
pw.print(" publicDir="); pw.print(info.publicSourceDir);
pw.print(" data="); pw.println(info.dataDir);
pw.print(prefix); pw.print("packageList="); pw.println(pkgList);
+ pw.print(prefix); pw.print("compat="); pw.println(compat);
if (instrumentationClass != null || instrumentationProfileFile != null
|| instrumentationArguments != null) {
pw.print(prefix); pw.print("instrumentationClass=");