summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dianne Hackborn <hackbod@google.com> 2011-05-27 16:45:31 -0700
committer Dianne Hackborn <hackbod@google.com> 2011-05-27 16:49:29 -0700
commit8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d (patch)
treea676c6b0daf45a90b600d3268bb37e81f23a2275
parentb96cbbd11c4590bec846212c33361e02293f18b5 (diff)
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 c151e3250a31..e42cacadac5c 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 65b3258c9404..080cbda797c4 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 d27cbdaaa053..33c12f46a1d1 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 a704f8822709..65ea4f4a7e3e 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 221b59b8307a..8949f48842f4 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 a63ffaef33c7..5465e370e687 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=");