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