diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-05-11 17:34:49 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2011-05-12 13:28:45 -0700 |
commit | 0f1de9adde0b52d2a385a76232bd7ac30c3eeea2 (patch) | |
tree | 6d30064324ea987411955a88cb0272ddb27d39b2 /services | |
parent | f3cdea937b8b659f959d5e77f4a17f749f85c6ae (diff) | |
download | frameworks_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')
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); + } + } + } +} |