summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-05-11 17:34:49 -0700
committerDianne Hackborn <hackbod@google.com>2011-05-12 13:28:45 -0700
commit0f1de9adde0b52d2a385a76232bd7ac30c3eeea2 (patch)
tree6d30064324ea987411955a88cb0272ddb27d39b2 /services
parentf3cdea937b8b659f959d5e77f4a17f749f85c6ae (diff)
downloadframeworks_base-0f1de9adde0b52d2a385a76232bd7ac30c3eeea2.zip
frameworks_base-0f1de9adde0b52d2a385a76232bd7ac30c3eeea2.tar.gz
frameworks_base-0f1de9adde0b52d2a385a76232bd7ac30c3eeea2.tar.bz2
New compat mode front end: UI and persistence.
Adds a really crappy UI for toggling compat mode. Persists compat mode selection across boots. Turns on compat mode by default for newly installed apps. Change-Id: Idc83494397bd17c41450bc9e9a05e4386c509399
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/PackageManagerService.java7
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java112
-rw-r--r--services/java/com/android/server/am/CompatModePackages.java295
3 files changed, 338 insertions, 76 deletions
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 5cd942c..4a66a40 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -8088,18 +8088,11 @@ class PackageManagerService extends IPackageManager.Stub {
Settings() {
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
- // TODO(oam): This secure dir creation needs to be moved somewhere else (later)
- File systemSecureDir = new File(dataDir, "secure/system");
systemDir.mkdirs();
- systemSecureDir.mkdirs();
FileUtils.setPermissions(systemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
- FileUtils.setPermissions(systemSecureDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
mSettingsFilename = new File(systemDir, "packages.xml");
mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
mPackageListFilename = new File(systemDir, "packages.list");
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 811221e..6a5ca1f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -550,7 +550,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* Packages that the user has asked to have run in screen size
* compatibility mode instead of filling the screen.
*/
- final HashSet<String> mScreenCompatPackages = new HashSet<String>();
+ final CompatModePackages mCompatModePackages;
/**
* Set of PendingResultRecord objects that are currently active.
@@ -1485,6 +1485,8 @@ public final class ActivityManagerService extends ActivityManagerNative
mConfiguration.locale = Locale.getDefault();
mProcessStats.init();
+ mCompatModePackages = new CompatModePackages(this, systemDir);
+
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
@@ -2099,70 +2101,30 @@ public final class ActivityManagerService extends ActivityManagerNative
}
CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
- return new CompatibilityInfo(ai, mConfiguration.screenLayout,
- mScreenCompatPackages.contains(ai.packageName));
+ return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
}
- public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) {
+ public int getFrontActivityScreenCompatMode() {
synchronized (this) {
- ApplicationInfo ai = null;
- try {
- ai = AppGlobals.getPackageManager().
- getApplicationInfo(packageName, STOCK_PM_FLAGS);
- } catch (RemoteException e) {
- }
- if (ai == null) {
- Slog.w(TAG, "setPackageScreenCompatMode failed: unknown package " + packageName);
- return;
- }
- boolean changed = false;
- if (compatEnabled) {
- if (!mScreenCompatPackages.contains(packageName)) {
- changed = true;
- mScreenCompatPackages.add(packageName);
- }
- } else {
- if (mScreenCompatPackages.contains(packageName)) {
- changed = true;
- mScreenCompatPackages.remove(packageName);
- }
- }
- if (changed) {
- CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai);
+ return mCompatModePackages.getFrontActivityScreenCompatModeLocked();
+ }
+ }
- // Tell all processes that loaded this package about the change.
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
- if (!app.pkgList.contains(packageName)) {
- continue;
- }
- try {
- if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "
- + app.processName + " new compat " + ci);
- app.thread.updatePackageCompatibilityInfo(packageName, ci);
- }
- } catch (Exception e) {
- }
- }
+ public void setFrontActivityScreenCompatMode(int mode) {
+ synchronized (this) {
+ mCompatModePackages.setFrontActivityScreenCompatModeLocked(mode);
+ }
+ }
- // All activities that came from the packge must be
- // restarted as if there was a config change.
- for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
- ActivityRecord a = (ActivityRecord)mMainStack.mHistory.get(i);
- if (a.info.packageName.equals(packageName)) {
- a.forceNewConfig = true;
- }
- }
+ public int getPackageScreenCompatMode(String packageName) {
+ synchronized (this) {
+ return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
+ }
+ }
- ActivityRecord starting = mMainStack.topRunningActivityLocked(null);
- if (starting != null) {
- mMainStack.ensureActivityConfigurationLocked(starting, 0);
- // And we need to make sure at this point that all other activities
- // are made visible with the correct configuration.
- mMainStack.ensureActivitiesVisibleLocked(starting, 0);
- }
- }
+ public void setPackageScreenCompatMode(String packageName, int mode) {
+ synchronized (this) {
+ mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
}
}
@@ -7855,9 +7817,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
pw.println(" mConfiguration: " + mConfiguration);
pw.println(" mConfigWillChange: " + mMainStack.mConfigWillChange);
- if (mScreenCompatPackages.size() > 0) {
+ if (mCompatModePackages.getPackages().size() > 0) {
pw.print(" mScreenCompatPackages=");
- pw.println(mScreenCompatPackages);
+ pw.println(mCompatModePackages.getPackages());
}
pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
@@ -10706,10 +10668,10 @@ public final class ActivityManagerService extends ActivityManagerNative
// Handle special intents: if this broadcast is from the package
// manager about a package being removed, we need to remove all of
// its activities from the history stack.
- final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
+ final boolean uidRemoved = Intent.ACTION_UID_REMOVED.equals(
intent.getAction());
- if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
- || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
+ || Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
|| Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
|| uidRemoved) {
if (checkComponentPermission(
@@ -10746,7 +10708,7 @@ public final class ActivityManagerService extends ActivityManagerNative
forceStopPackageLocked(ssp,
intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
}
- if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
new String[] {ssp});
}
@@ -10762,6 +10724,18 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
+
+ // 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);
+ }
+ }
}
/*
@@ -10920,9 +10894,9 @@ public final class ActivityManagerService extends ActivityManagerNative
// broadcast or such for apps, but we'd like to deliberately make
// this decision.
String skipPackages[] = null;
- if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
- || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
- || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
+ if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
+ || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
+ || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
Uri data = intent.getData();
if (data != null) {
String pkgName = data.getSchemeSpecificPart();
@@ -10930,7 +10904,7 @@ public final class ActivityManagerService extends ActivityManagerNative
skipPackages = new String[] { pkgName };
}
}
- } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
if (skipPackages != null && (skipPackages.length > 0)) {
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
new file mode 100644
index 0000000..1faf8da
--- /dev/null
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -0,0 +1,295 @@
+package com.android.server.am;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FastXmlSerializer;
+
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.res.CompatibilityInfo;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.Xml;
+
+public class CompatModePackages {
+ private final String TAG = ActivityManagerService.TAG;
+ private final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
+
+ private final ActivityManagerService mService;
+ private final AtomicFile mFile;
+
+ private final HashSet<String> mPackages = new HashSet<String>();
+
+ private static final int MSG_WRITE = 1;
+
+ private final Handler mHandler = new Handler() {
+ @Override public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_WRITE:
+ saveCompatModes();
+ break;
+ default:
+ super.handleMessage(msg);
+ break;
+ }
+ }
+ };
+
+ public CompatModePackages(ActivityManagerService service, File systemDir) {
+ mService = service;
+ mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"));
+
+ FileInputStream fis = null;
+ try {
+ fis = mFile.openRead();
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, null);
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.START_TAG) {
+ eventType = parser.next();
+ }
+ String tagName = parser.getName();
+ if ("compat-packages".equals(tagName)) {
+ eventType = parser.next();
+ do {
+ if (eventType == XmlPullParser.START_TAG) {
+ tagName = parser.getName();
+ if (parser.getDepth() == 2) {
+ if ("pkg".equals(tagName)) {
+ String pkg = parser.getAttributeValue(null, "name");
+ if (pkg != null) {
+ mPackages.add(pkg);
+ }
+ }
+ }
+ }
+ eventType = parser.next();
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+ }
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Error reading compat-packages", e);
+ } catch (java.io.IOException e) {
+ if (fis != null) Slog.w(TAG, "Error reading compat-packages", e);
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (java.io.IOException e1) {
+ }
+ }
+ }
+ }
+
+ public HashSet<String> getPackages() {
+ return mPackages;
+ }
+
+ public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
+ return new CompatibilityInfo(ai, mService.mConfiguration.screenLayout,
+ mPackages.contains(ai.packageName));
+ }
+
+ private int computeCompatModeLocked(ApplicationInfo ai) {
+ boolean enabled = mPackages.contains(ai.packageName);
+ CompatibilityInfo info = new CompatibilityInfo(ai,
+ mService.mConfiguration.screenLayout, enabled);
+ if (info.alwaysSupportsScreen()) {
+ return ActivityManager.COMPAT_MODE_NEVER;
+ }
+ if (info.neverSupportsScreen()) {
+ return ActivityManager.COMPAT_MODE_ALWAYS;
+ }
+ return enabled ? ActivityManager.COMPAT_MODE_ENABLED
+ : ActivityManager.COMPAT_MODE_DISABLED;
+ }
+
+ public int getFrontActivityScreenCompatModeLocked() {
+ ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+ if (r == null) {
+ return ActivityManager.COMPAT_MODE_UNKNOWN;
+ }
+ return computeCompatModeLocked(r.info.applicationInfo);
+ }
+
+ public void setFrontActivityScreenCompatModeLocked(int mode) {
+ ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+ if (r == null) {
+ Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
+ return;
+ }
+ setPackageScreenCompatModeLocked(r.info.applicationInfo, mode);
+ }
+
+ public int getPackageScreenCompatModeLocked(String packageName) {
+ ApplicationInfo ai = null;
+ try {
+ ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0);
+ } catch (RemoteException e) {
+ }
+ if (ai == null) {
+ return ActivityManager.COMPAT_MODE_UNKNOWN;
+ }
+ return computeCompatModeLocked(ai);
+ }
+
+ public void setPackageScreenCompatModeLocked(String packageName, int mode) {
+ ApplicationInfo ai = null;
+ try {
+ ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0);
+ } catch (RemoteException e) {
+ }
+ if (ai == null) {
+ Slog.w(TAG, "setPackageScreenCompatMode failed: unknown package " + packageName);
+ return;
+ }
+ setPackageScreenCompatModeLocked(ai, mode);
+ }
+
+ private void setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode) {
+ final String packageName = ai.packageName;
+
+ boolean changed = false;
+ boolean enable;
+ switch (mode) {
+ case ActivityManager.COMPAT_MODE_DISABLED:
+ enable = false;
+ break;
+ case ActivityManager.COMPAT_MODE_ENABLED:
+ enable = true;
+ break;
+ case ActivityManager.COMPAT_MODE_TOGGLE:
+ enable = !mPackages.contains(packageName);
+ break;
+ default:
+ Slog.w(TAG, "Unknown screen compat mode req #" + mode + "; ignoring");
+ return;
+ }
+ if (enable) {
+ if (!mPackages.contains(packageName)) {
+ changed = true;
+ mPackages.add(packageName);
+ }
+ } else {
+ if (mPackages.contains(packageName)) {
+ changed = true;
+ mPackages.remove(packageName);
+ }
+ }
+ if (changed) {
+ 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;
+ }
+
+ mHandler.removeMessages(MSG_WRITE);
+ Message msg = mHandler.obtainMessage(MSG_WRITE);
+ mHandler.sendMessageDelayed(msg, 10000);
+
+ // 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);
+ if (!app.pkgList.contains(packageName)) {
+ continue;
+ }
+ try {
+ if (app.thread != null) {
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "
+ + app.processName + " new compat " + ci);
+ app.thread.updatePackageCompatibilityInfo(packageName, ci);
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ // 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
+ // are made visible with the correct configuration.
+ mService.mMainStack.ensureActivitiesVisibleLocked(starting, 0);
+ }
+ }
+ }
+
+ void saveCompatModes() {
+ HashSet<String> pkgs;
+ synchronized (mService) {
+ pkgs = new HashSet<String>(mPackages);
+ }
+
+ FileOutputStream fos = null;
+
+ try {
+ fos = mFile.startWrite();
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(fos, "utf-8");
+ out.startDocument(null, true);
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ out.startTag(null, "compat-packages");
+
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ final int screenLayout = mService.mConfiguration.screenLayout;
+ final Iterator<String> it = pkgs.iterator();
+ while (it.hasNext()) {
+ String pkg = it.next();
+ ApplicationInfo ai = null;
+ try {
+ ai = pm.getApplicationInfo(pkg, 0);
+ } catch (RemoteException e) {
+ }
+ if (ai == null) {
+ continue;
+ }
+ CompatibilityInfo info = new CompatibilityInfo(ai, screenLayout, false);
+ if (info.alwaysSupportsScreen()) {
+ continue;
+ }
+ if (info.neverSupportsScreen()) {
+ continue;
+ }
+ out.startTag(null, "pkg");
+ out.attribute(null, "name", pkg);
+ out.endTag(null, "pkg");
+ }
+
+ out.endTag(null, "compat-packages");
+ out.endDocument();
+
+ mFile.finishWrite(fos);
+ } catch (java.io.IOException e1) {
+ Slog.w(TAG, "Error writing compat packages", e1);
+ if (fos != null) {
+ mFile.failWrite(fos);
+ }
+ }
+ }
+}