1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; 20 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 21 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 22 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; 23 24 import android.app.ActivityManager; 25 import android.app.AppGlobals; 26 import android.app.compat.CompatChanges; 27 import android.compat.annotation.ChangeId; 28 import android.compat.annotation.Disabled; 29 import android.compat.annotation.EnabledSince; 30 import android.compat.annotation.Overridable; 31 import android.content.pm.ApplicationInfo; 32 import android.content.pm.IPackageManager; 33 import android.content.res.CompatibilityInfo; 34 import android.content.res.Configuration; 35 import android.os.Build; 36 import android.os.Handler; 37 import android.os.Looper; 38 import android.os.Message; 39 import android.os.RemoteException; 40 import android.os.UserHandle; 41 import android.util.AtomicFile; 42 import android.util.DisplayMetrics; 43 import android.util.Slog; 44 import android.util.SparseArray; 45 import android.util.TypedXmlPullParser; 46 import android.util.TypedXmlSerializer; 47 import android.util.Xml; 48 49 import com.android.internal.protolog.common.ProtoLog; 50 51 import org.xmlpull.v1.XmlPullParser; 52 import org.xmlpull.v1.XmlPullParserException; 53 54 import java.io.File; 55 import java.io.FileInputStream; 56 import java.io.FileOutputStream; 57 import java.util.HashMap; 58 import java.util.Iterator; 59 import java.util.Map; 60 61 public final class CompatModePackages { 62 /** 63 * #DOWNSCALED_INVERSE is the gatekeeper of all per-app buffer inverse 64 * downscale changes. Enabling this change will allow the following scaling factors: 65 * #DOWNSCALE_90 66 * #DOWNSCALE_85 67 * #DOWNSCALE_80 68 * #DOWNSCALE_75 69 * #DOWNSCALE_70 70 * #DOWNSCALE_65 71 * #DOWNSCALE_60 72 * #DOWNSCALE_55 73 * #DOWNSCALE_50 74 * #DOWNSCALE_45 75 * #DOWNSCALE_40 76 * #DOWNSCALE_35 77 * #DOWNSCALE_30 78 * 79 * If #DOWNSCALED_INVERSE is enabled for an app package, then the app 80 * will be forcibly resized to the lowest enabled scaling factor e.g. 1/0.8 if both 1/0.8 and 81 * 1/0.7 (* 100%) were enabled. 82 * 83 * When both #DOWNSCALED_INVERSE 84 * and #DOWNSCALED are enabled, then 85 * #DOWNSCALED_INVERSE takes precedence. 86 */ 87 @ChangeId 88 @Disabled 89 @Overridable 90 public static final long DOWNSCALED_INVERSE = 273564678L; // This is a Bug ID. 91 92 /** 93 * #DOWNSCALED is the gatekeeper of all per-app buffer downscaling 94 * changes. Enabling this change will allow the following scaling factors: 95 * #DOWNSCALE_90 96 * #DOWNSCALE_85 97 * #DOWNSCALE_80 98 * #DOWNSCALE_75 99 * #DOWNSCALE_70 100 * #DOWNSCALE_65 101 * #DOWNSCALE_60 102 * #DOWNSCALE_55 103 * #DOWNSCALE_50 104 * #DOWNSCALE_45 105 * #DOWNSCALE_40 106 * #DOWNSCALE_35 107 * #DOWNSCALE_30 108 * 109 * If #DOWNSCALED is enabled for an app package, then the app will be 110 * forcibly resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were 111 * enabled. 112 * 113 * When both #DOWNSCALED_INVERSE 114 * and #DOWNSCALED are enabled, then 115 * #DOWNSCALED_INVERSE takes precedence. 116 */ 117 @ChangeId 118 @Disabled 119 @Overridable 120 public static final long DOWNSCALED = 168419799L; 121 122 /** 123 * With #DOWNSCALED enabled, subsequently enabling change-id 124 * #DOWNSCALE_90 for a package will force the app to assume it's 125 * running on a display with 90% the vertical and horizontal resolution of the real display. 126 * 127 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 128 * running on a display with 111.11% the vertical and horizontal resolution of the real display 129 */ 130 @ChangeId 131 @Disabled 132 @Overridable 133 public static final long DOWNSCALE_90 = 182811243L; 134 135 /** 136 * With #DOWNSCALED enabled, subsequently enabling change-id 137 * #DOWNSCALE_85 for a package will force the app to assume it's 138 * running on a display with 85% the vertical and horizontal resolution of the real display. 139 * 140 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 141 * running on a display with 117.65% the vertical and horizontal resolution of the real display 142 */ 143 @ChangeId 144 @Disabled 145 @Overridable 146 public static final long DOWNSCALE_85 = 189969734L; 147 148 /** 149 * With #DOWNSCALED enabled, subsequently enabling change-id 150 * #DOWNSCALE_80 for a package will force the app to assume it's 151 * running on a display with 80% the vertical and horizontal resolution of the real display. 152 * 153 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 154 * running on a display with 125% the vertical and horizontal resolution of the real display 155 */ 156 @ChangeId 157 @Disabled 158 @Overridable 159 public static final long DOWNSCALE_80 = 176926753L; 160 161 /** 162 * With #DOWNSCALED enabled, subsequently enabling change-id 163 * #DOWNSCALE_75 for a package will force the app to assume it's 164 * running on a display with 75% the vertical and horizontal resolution of the real display. 165 * 166 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 167 * running on a display with 133.33% the vertical and horizontal resolution of the real display 168 */ 169 @ChangeId 170 @Disabled 171 @Overridable 172 public static final long DOWNSCALE_75 = 189969779L; 173 174 /** 175 * With #DOWNSCALED enabled, subsequently enabling change-id 176 * #DOWNSCALE_70 for a package will force the app to assume it's 177 * running on a display with 70% the vertical and horizontal resolution of the real display. 178 * 179 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 180 * running on a display with 142.86% the vertical and horizontal resolution of the real display 181 */ 182 @ChangeId 183 @Disabled 184 @Overridable 185 public static final long DOWNSCALE_70 = 176926829L; 186 187 /** 188 * With #DOWNSCALED enabled, subsequently enabling change-id 189 * #DOWNSCALE_65 for a package will force the app to assume it's 190 * running on a display with 65% the vertical and horizontal resolution of the real display. 191 * 192 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 193 * running on a display with 153.85% the vertical and horizontal resolution of the real display 194 */ 195 @ChangeId 196 @Disabled 197 @Overridable 198 public static final long DOWNSCALE_65 = 189969744L; 199 200 /** 201 * With #DOWNSCALED enabled, subsequently enabling change-id 202 * #DOWNSCALE_60 for a package will force the app to assume it's 203 * running on a display with 60% the vertical and horizontal resolution of the real display. 204 * 205 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 206 * running on a display with 166.67% the vertical and horizontal resolution of the real display 207 */ 208 @ChangeId 209 @Disabled 210 @Overridable 211 public static final long DOWNSCALE_60 = 176926771L; 212 213 /** 214 * With #DOWNSCALED enabled, subsequently enabling change-id 215 * #DOWNSCALE_55 for a package will force the app to assume it's 216 * running on a display with 55% the vertical and horizontal resolution of the real display. 217 * 218 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 219 * running on a display with 181.82% the vertical and horizontal resolution of the real display 220 */ 221 @ChangeId 222 @Disabled 223 @Overridable 224 public static final long DOWNSCALE_55 = 189970036L; 225 226 /** 227 * With #DOWNSCALED enabled, subsequently enabling change-id 228 * #DOWNSCALE_50 for a package will force the app to assume it's 229 * running on a display with 50% vertical and horizontal resolution of the real display. 230 * 231 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 232 * running on a display with 200% the vertical and horizontal resolution of the real display 233 */ 234 @ChangeId 235 @Disabled 236 @Overridable 237 public static final long DOWNSCALE_50 = 176926741L; 238 239 /** 240 * With #DOWNSCALED enabled, subsequently enabling change-id 241 * #DOWNSCALE_45 for a package will force the app to assume it's 242 * running on a display with 45% the vertical and horizontal resolution of the real display. 243 * 244 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 245 * running on a display with 222.22% the vertical and horizontal resolution of the real display 246 */ 247 @ChangeId 248 @Disabled 249 @Overridable 250 public static final long DOWNSCALE_45 = 189969782L; 251 252 /** 253 * With #DOWNSCALED enabled, subsequently enabling change-id 254 * #DOWNSCALE_40 for a package will force the app to assume it's 255 * running on a display with 40% the vertical and horizontal resolution of the real display. 256 * 257 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 258 * running on a display with 250% the vertical and horizontal resolution of the real display 259 */ 260 @ChangeId 261 @Disabled 262 @Overridable 263 public static final long DOWNSCALE_40 = 189970038L; 264 265 /** 266 * With #DOWNSCALED enabled, subsequently enabling change-id 267 * #DOWNSCALE_35 for a package will force the app to assume it's 268 * running on a display with 35% the vertical and horizontal resolution of the real display. 269 * 270 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 271 * running on a display with 285.71% the vertical and horizontal resolution of the real display 272 */ 273 @ChangeId 274 @Disabled 275 @Overridable 276 public static final long DOWNSCALE_35 = 189969749L; 277 278 /** 279 * With #DOWNSCALED enabled, subsequently enabling change-id 280 * #DOWNSCALE_30 for a package will force the app to assume it's 281 * running on a display with 30% the vertical and horizontal resolution of the real display. 282 * 283 * With #DOWNSCALED_INVERSE enabled will force the app to assume it's 284 * running on a display with 333.33% the vertical and horizontal resolution of the real display 285 */ 286 @ChangeId 287 @Disabled 288 @Overridable 289 public static final long DOWNSCALE_30 = 189970040L; 290 291 /** 292 * On Android TV applications that target pre-S are not expecting to receive a Window larger 293 * than 1080p, so if needed we are downscaling their Windows to 1080p. 294 * However, applications that target S and greater release version are expected to be able to 295 * handle any Window size, so we should not downscale their Windows. 296 */ 297 @ChangeId 298 @Overridable 299 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) 300 private static final long DO_NOT_DOWNSCALE_TO_1080P_ON_TV = 157629738L; // This is a Bug ID. 301 302 private static final int MSG_WRITE = 300; 303 304 private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_ATM; 305 306 // Compatibility state: no longer ask user to select the mode. 307 private static final int COMPAT_FLAG_DONT_ASK = 1 << 0; 308 309 // Compatibility state: compatibility mode is enabled. 310 private static final int COMPAT_FLAG_ENABLED = 1 << 1; 311 312 private final class CompatHandler extends Handler { CompatHandler(Looper looper)313 public CompatHandler(Looper looper) { 314 super(looper, null, true); 315 } 316 317 @Override handleMessage(Message msg)318 public void handleMessage(Message msg) { 319 switch (msg.what) { 320 case MSG_WRITE: 321 saveCompatModes(); 322 break; 323 } 324 } 325 } 326 327 private final ActivityTaskManagerService mService; 328 private final AtomicFile mFile; 329 private final HashMap<String, Integer> mPackages = new HashMap<>(); 330 private final CompatHandler mHandler; 331 CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler)332 public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) { 333 mService = service; 334 mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"), "compat-mode"); 335 mHandler = new CompatHandler(handler.getLooper()); 336 337 FileInputStream fis = null; 338 try { 339 fis = mFile.openRead(); 340 TypedXmlPullParser parser = Xml.resolvePullParser(fis); 341 int eventType = parser.getEventType(); 342 while (eventType != XmlPullParser.START_TAG && 343 eventType != XmlPullParser.END_DOCUMENT) { 344 eventType = parser.next(); 345 } 346 if (eventType == XmlPullParser.END_DOCUMENT) { 347 return; 348 } 349 350 String tagName = parser.getName(); 351 if ("compat-packages".equals(tagName)) { 352 eventType = parser.next(); 353 do { 354 if (eventType == XmlPullParser.START_TAG) { 355 tagName = parser.getName(); 356 if (parser.getDepth() == 2) { 357 if ("pkg".equals(tagName)) { 358 String pkg = parser.getAttributeValue(null, "name"); 359 if (pkg != null) { 360 int modeInt = parser.getAttributeInt(null, "mode", 0); 361 mPackages.put(pkg, modeInt); 362 } 363 } 364 } 365 } 366 eventType = parser.next(); 367 } while (eventType != XmlPullParser.END_DOCUMENT); 368 } 369 } catch (XmlPullParserException e) { 370 Slog.w(TAG, "Error reading compat-packages", e); 371 } catch (java.io.IOException e) { 372 if (fis != null) Slog.w(TAG, "Error reading compat-packages", e); 373 } finally { 374 if (fis != null) { 375 try { 376 fis.close(); 377 } catch (java.io.IOException e1) { 378 } 379 } 380 } 381 } 382 getPackages()383 public HashMap<String, Integer> getPackages() { 384 return mPackages; 385 } 386 getPackageFlags(String packageName)387 private int getPackageFlags(String packageName) { 388 Integer flags = mPackages.get(packageName); 389 return flags != null ? flags : 0; 390 } 391 handlePackageDataClearedLocked(String packageName)392 public void handlePackageDataClearedLocked(String packageName) { 393 // User has explicitly asked to clear all associated data. 394 removePackage(packageName); 395 } 396 handlePackageUninstalledLocked(String packageName)397 public void handlePackageUninstalledLocked(String packageName) { 398 // Clear settings when app is uninstalled since this is an explicit 399 // signal from the user to remove the app and all associated data. 400 removePackage(packageName); 401 } 402 removePackage(String packageName)403 private void removePackage(String packageName) { 404 if (mPackages.containsKey(packageName)) { 405 mPackages.remove(packageName); 406 scheduleWrite(); 407 } 408 } 409 handlePackageAddedLocked(String packageName, boolean updated)410 public void handlePackageAddedLocked(String packageName, boolean updated) { 411 ApplicationInfo ai = null; 412 try { 413 ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0); 414 } catch (RemoteException e) { 415 } 416 if (ai == null) { 417 return; 418 } 419 CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); 420 final boolean mayCompat = !ci.alwaysSupportsScreen() 421 && !ci.neverSupportsScreen(); 422 423 if (updated) { 424 // Update -- if the app no longer can run in compat mode, clear 425 // any current settings for it. 426 if (!mayCompat && mPackages.containsKey(packageName)) { 427 mPackages.remove(packageName); 428 scheduleWrite(); 429 } 430 } 431 } 432 scheduleWrite()433 private void scheduleWrite() { 434 mHandler.removeMessages(MSG_WRITE); 435 Message msg = mHandler.obtainMessage(MSG_WRITE); 436 mHandler.sendMessageDelayed(msg, 10000); 437 } 438 compatibilityInfoForPackageLocked(ApplicationInfo ai)439 public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { 440 final boolean forceCompat = getPackageCompatModeEnabledLocked(ai); 441 final float compatScale = getCompatScale(ai.packageName, ai.uid); 442 final Configuration config = mService.getGlobalConfiguration(); 443 return new CompatibilityInfo(ai, config.screenLayout, config.smallestScreenWidthDp, 444 forceCompat, compatScale); 445 } 446 getCompatScale(String packageName, int uid)447 float getCompatScale(String packageName, int uid) { 448 final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); 449 final boolean isDownscaledEnabled = CompatChanges.isChangeEnabled( 450 DOWNSCALED, packageName, userHandle); 451 final boolean isDownscaledInverseEnabled = CompatChanges.isChangeEnabled( 452 DOWNSCALED_INVERSE, packageName, userHandle); 453 if (isDownscaledEnabled || isDownscaledInverseEnabled) { 454 final float scalingFactor = getScalingFactor(packageName, userHandle); 455 if (scalingFactor != 1f) { 456 // For Upscaling the returned factor must be scalingFactor 457 // For Downscaling the returned factor must be 1f / scalingFactor 458 return isDownscaledInverseEnabled ? scalingFactor : 1f / scalingFactor; 459 } 460 } 461 462 if (mService.mHasLeanbackFeature) { 463 final Configuration config = mService.getGlobalConfiguration(); 464 final float density = config.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT; 465 final int smallestScreenWidthPx = (int) (config.smallestScreenWidthDp * density + .5f); 466 if (smallestScreenWidthPx > 1080 && !CompatChanges.isChangeEnabled( 467 DO_NOT_DOWNSCALE_TO_1080P_ON_TV, packageName, userHandle)) { 468 return smallestScreenWidthPx / 1080f; 469 } 470 } 471 472 return 1f; 473 } 474 getScalingFactor(String packageName, UserHandle userHandle)475 private static float getScalingFactor(String packageName, UserHandle userHandle) { 476 if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) { 477 return 0.9f; 478 } 479 if (CompatChanges.isChangeEnabled(DOWNSCALE_85, packageName, userHandle)) { 480 return 0.85f; 481 } 482 if (CompatChanges.isChangeEnabled(DOWNSCALE_80, packageName, userHandle)) { 483 return 0.8f; 484 } 485 if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) { 486 return 0.75f; 487 } 488 if (CompatChanges.isChangeEnabled(DOWNSCALE_70, packageName, userHandle)) { 489 return 0.7f; 490 } 491 if (CompatChanges.isChangeEnabled(DOWNSCALE_65, packageName, userHandle)) { 492 return 0.65f; 493 } 494 if (CompatChanges.isChangeEnabled(DOWNSCALE_60, packageName, userHandle)) { 495 return 0.6f; 496 } 497 if (CompatChanges.isChangeEnabled(DOWNSCALE_55, packageName, userHandle)) { 498 return 0.55f; 499 } 500 if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) { 501 return 0.5f; 502 } 503 if (CompatChanges.isChangeEnabled(DOWNSCALE_45, packageName, userHandle)) { 504 return 0.45f; 505 } 506 if (CompatChanges.isChangeEnabled(DOWNSCALE_40, packageName, userHandle)) { 507 return 0.4f; 508 } 509 if (CompatChanges.isChangeEnabled(DOWNSCALE_35, packageName, userHandle)) { 510 return 0.35f; 511 } 512 if (CompatChanges.isChangeEnabled(DOWNSCALE_30, packageName, userHandle)) { 513 return 0.3f; 514 } 515 return 1f; 516 } 517 computeCompatModeLocked(ApplicationInfo ai)518 public int computeCompatModeLocked(ApplicationInfo ai) { 519 final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai); 520 if (info.alwaysSupportsScreen()) { 521 return ActivityManager.COMPAT_MODE_NEVER; 522 } 523 if (info.neverSupportsScreen()) { 524 return ActivityManager.COMPAT_MODE_ALWAYS; 525 } 526 return getPackageCompatModeEnabledLocked(ai) ? ActivityManager.COMPAT_MODE_ENABLED 527 : ActivityManager.COMPAT_MODE_DISABLED; 528 } 529 getPackageAskCompatModeLocked(String packageName)530 public boolean getPackageAskCompatModeLocked(String packageName) { 531 return (getPackageFlags(packageName)&COMPAT_FLAG_DONT_ASK) == 0; 532 } 533 setPackageAskCompatModeLocked(String packageName, boolean ask)534 public void setPackageAskCompatModeLocked(String packageName, boolean ask) { 535 setPackageFlagLocked(packageName, COMPAT_FLAG_DONT_ASK, ask); 536 } 537 getPackageCompatModeEnabledLocked(ApplicationInfo ai)538 private boolean getPackageCompatModeEnabledLocked(ApplicationInfo ai) { 539 return (getPackageFlags(ai.packageName) & COMPAT_FLAG_ENABLED) != 0; 540 } 541 setPackageFlagLocked(String packageName, int flag, boolean set)542 private void setPackageFlagLocked(String packageName, int flag, boolean set) { 543 final int curFlags = getPackageFlags(packageName); 544 final int newFlags = set ? (curFlags & ~flag) : (curFlags | flag); 545 if (curFlags != newFlags) { 546 if (newFlags != 0) { 547 mPackages.put(packageName, newFlags); 548 } else { 549 mPackages.remove(packageName); 550 } 551 scheduleWrite(); 552 } 553 } 554 getPackageScreenCompatModeLocked(String packageName)555 public int getPackageScreenCompatModeLocked(String packageName) { 556 ApplicationInfo ai = null; 557 try { 558 ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0); 559 } catch (RemoteException e) { 560 } 561 if (ai == null) { 562 return ActivityManager.COMPAT_MODE_UNKNOWN; 563 } 564 return computeCompatModeLocked(ai); 565 } 566 setPackageScreenCompatModeLocked(String packageName, int mode)567 public void setPackageScreenCompatModeLocked(String packageName, int mode) { 568 ApplicationInfo ai = null; 569 try { 570 ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0); 571 } catch (RemoteException e) { 572 } 573 if (ai == null) { 574 Slog.w(TAG, "setPackageScreenCompatMode failed: unknown package " + packageName); 575 return; 576 } 577 setPackageScreenCompatModeLocked(ai, mode); 578 } 579 setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode)580 void setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode) { 581 final String packageName = ai.packageName; 582 583 int curFlags = getPackageFlags(packageName); 584 585 boolean enable; 586 switch (mode) { 587 case ActivityManager.COMPAT_MODE_DISABLED: 588 enable = false; 589 break; 590 case ActivityManager.COMPAT_MODE_ENABLED: 591 enable = true; 592 break; 593 case ActivityManager.COMPAT_MODE_TOGGLE: 594 enable = (curFlags&COMPAT_FLAG_ENABLED) == 0; 595 break; 596 default: 597 Slog.w(TAG, "Unknown screen compat mode req #" + mode + "; ignoring"); 598 return; 599 } 600 601 int newFlags = curFlags; 602 if (enable) { 603 newFlags |= COMPAT_FLAG_ENABLED; 604 } else { 605 newFlags &= ~COMPAT_FLAG_ENABLED; 606 } 607 608 CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); 609 if (ci.alwaysSupportsScreen()) { 610 Slog.w(TAG, "Ignoring compat mode change of " + packageName 611 + "; compatibility never needed"); 612 newFlags = 0; 613 } 614 if (ci.neverSupportsScreen()) { 615 Slog.w(TAG, "Ignoring compat mode change of " + packageName 616 + "; compatibility always needed"); 617 newFlags = 0; 618 } 619 620 if (newFlags != curFlags) { 621 if (newFlags != 0) { 622 mPackages.put(packageName, newFlags); 623 } else { 624 mPackages.remove(packageName); 625 } 626 627 // Need to get compatibility info in new state. 628 ci = compatibilityInfoForPackageLocked(ai); 629 630 scheduleWrite(); 631 632 final Task rootTask = mService.getTopDisplayFocusedRootTask(); 633 ActivityRecord starting = rootTask.restartPackage(packageName); 634 635 // Tell all processes that loaded this package about the change. 636 SparseArray<WindowProcessController> pidMap = mService.mProcessMap.getPidMap(); 637 for (int i = pidMap.size() - 1; i >= 0; i--) { 638 final WindowProcessController app = pidMap.valueAt(i); 639 if (!app.mPkgList.contains(packageName)) { 640 continue; 641 } 642 try { 643 if (app.hasThread()) { 644 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s " 645 + "new compat %s", app.mName, ci); 646 app.getThread().updatePackageCompatibilityInfo(packageName, ci); 647 } 648 } catch (Exception e) { 649 } 650 } 651 652 if (starting != null) { 653 starting.ensureActivityConfiguration(0 /* globalChanges */, 654 false /* preserveWindow */); 655 // And we need to make sure at this point that all other activities 656 // are made visible with the correct configuration. 657 rootTask.ensureActivitiesVisible(starting, 0, !PRESERVE_WINDOWS); 658 } 659 } 660 } 661 saveCompatModes()662 private void saveCompatModes() { 663 HashMap<String, Integer> pkgs; 664 synchronized (mService.mGlobalLock) { 665 pkgs = new HashMap<>(mPackages); 666 } 667 668 FileOutputStream fos = null; 669 670 try { 671 fos = mFile.startWrite(); 672 TypedXmlSerializer out = Xml.resolveSerializer(fos); 673 out.startDocument(null, true); 674 out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 675 out.startTag(null, "compat-packages"); 676 677 final IPackageManager pm = AppGlobals.getPackageManager(); 678 final Iterator<Map.Entry<String, Integer>> it = pkgs.entrySet().iterator(); 679 while (it.hasNext()) { 680 Map.Entry<String, Integer> entry = it.next(); 681 String pkg = entry.getKey(); 682 int mode = entry.getValue(); 683 if (mode == 0) { 684 continue; 685 } 686 ApplicationInfo ai = null; 687 try { 688 ai = pm.getApplicationInfo(pkg, 0, 0); 689 } catch (RemoteException e) { 690 } 691 if (ai == null) { 692 continue; 693 } 694 final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai); 695 if (info.alwaysSupportsScreen()) { 696 continue; 697 } 698 if (info.neverSupportsScreen()) { 699 continue; 700 } 701 out.startTag(null, "pkg"); 702 out.attribute(null, "name", pkg); 703 out.attributeInt(null, "mode", mode); 704 out.endTag(null, "pkg"); 705 } 706 707 out.endTag(null, "compat-packages"); 708 out.endDocument(); 709 710 mFile.finishWrite(fos); 711 } catch (java.io.IOException e1) { 712 Slog.w(TAG, "Error writing compat packages", e1); 713 if (fos != null) { 714 mFile.failWrite(fos); 715 } 716 } 717 } 718 } 719