Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5d37701 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android Git Automerger
Browse files

am 8ea5e1d7: Fix compat mode bugs when updating apps.

* commit '8ea5e1d7':
  Fix compat mode bugs when updating apps.
parents 528c49f1 8ea5e1d7
Loading
Loading
Loading
Loading
+65 −53
Original line number Diff line number Diff line
@@ -62,38 +62,20 @@ 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);
    }
@@ -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;
    }

    /**
@@ -515,6 +505,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;
+7 −9
Original line number Diff line number Diff line
@@ -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);
                }
                mCompatModePackages.handlePackageAddedLocked(ssp,
                        intent.getBooleanExtra(Intent.EXTRA_REPLACING, false));
            }
        }
+3 −0
Original line number Diff line number Diff line
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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) {
+62 −21
Original line number Diff line number Diff line
@@ -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;
        }

        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;
            newFlags = 0;
        }
        if (ci.neverSupportsScreen()) {
            Slog.w(TAG, "Ignoring compat mode change of " + packageName
                    + "; compatibility always needed");
                return;
            newFlags = 0;
        }

        if (newFlags != curFlags) {
            if (newFlags != 0) {
                mPackages.put(packageName, newFlags);
            } else {
                mPackages.remove(packageName);
            }

            // 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
Loading