diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-15 06:19:41 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-15 06:19:41 +0000 |
commit | 75b2c1bce561265d88f5b429f57ec38c7a2e83af (patch) | |
tree | b0bc61a7cc970849b665c592a87da2f5973155e4 | |
parent | 50790f20550a20b311328e23d135c91d1d69659a (diff) | |
parent | a91acc561e294fd5b23037f868cd031efd0441f6 (diff) | |
download | base-75b2c1bce561265d88f5b429f57ec38c7a2e83af.tar.gz |
Merge cherrypicks of [9735310, 9736237, 9736061, 9736062, 9736238, 9736299, 9736300, 9735211, 9735311] into qt-qpr1-c-release
Change-Id: I9cac8e969b6d1398612bfb86773fcd008d8decf2
3 files changed, 233 insertions, 31 deletions
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 838e7d3c0208..fe29a36ec45f 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -1329,7 +1329,7 @@ public final class ProcessList { final int procCount = procs.size(); for (int i = 0; i < procCount; i++) { final int procUid = procs.keyAt(i); - if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) { + if (!UserHandle.isCore(procUid) || !UserHandle.isSameUser(procUid, uid)) { // Don't use an app process or different user process for system component. continue; } diff --git a/services/core/java/com/android/server/wallpaper/GLHelper.java b/services/core/java/com/android/server/wallpaper/GLHelper.java new file mode 100644 index 000000000000..1d733f53f055 --- /dev/null +++ b/services/core/java/com/android/server/wallpaper/GLHelper.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wallpaper; + +import static android.opengl.EGL14.EGL_ALPHA_SIZE; +import static android.opengl.EGL14.EGL_BLUE_SIZE; +import static android.opengl.EGL14.EGL_CONFIG_CAVEAT; +import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; +import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY; +import static android.opengl.EGL14.EGL_DEPTH_SIZE; +import static android.opengl.EGL14.EGL_GREEN_SIZE; +import static android.opengl.EGL14.EGL_HEIGHT; +import static android.opengl.EGL14.EGL_NONE; +import static android.opengl.EGL14.EGL_NO_CONTEXT; +import static android.opengl.EGL14.EGL_NO_DISPLAY; +import static android.opengl.EGL14.EGL_NO_SURFACE; +import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; +import static android.opengl.EGL14.EGL_RED_SIZE; +import static android.opengl.EGL14.EGL_RENDERABLE_TYPE; +import static android.opengl.EGL14.EGL_STENCIL_SIZE; +import static android.opengl.EGL14.EGL_WIDTH; +import static android.opengl.EGL14.eglChooseConfig; +import static android.opengl.EGL14.eglCreateContext; +import static android.opengl.EGL14.eglCreatePbufferSurface; +import static android.opengl.EGL14.eglDestroyContext; +import static android.opengl.EGL14.eglDestroySurface; +import static android.opengl.EGL14.eglGetDisplay; +import static android.opengl.EGL14.eglGetError; +import static android.opengl.EGL14.eglInitialize; +import static android.opengl.EGL14.eglMakeCurrent; +import static android.opengl.EGL14.eglTerminate; +import static android.opengl.GLES20.GL_MAX_TEXTURE_SIZE; +import static android.opengl.GLES20.glGetIntegerv; + +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLSurface; +import android.opengl.GLUtils; +import android.os.SystemProperties; +import android.util.Log; + +class GLHelper { + private static final String TAG = GLHelper.class.getSimpleName(); + private static final int sMaxTextureSize; + + static { + int maxTextureSize = SystemProperties.getInt("sys.max_texture_size", 0); + sMaxTextureSize = maxTextureSize > 0 ? maxTextureSize : retrieveTextureSizeFromGL(); + } + + private static int retrieveTextureSizeFromGL() { + try { + String err; + + // Before we can retrieve info from GL, + // we have to create EGLContext, EGLConfig and EGLDisplay first. + // We will fail at querying info from GL once one of above failed. + // When this happens, we will use defValue instead. + EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay == null || eglDisplay == EGL_NO_DISPLAY) { + err = "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + if (!eglInitialize(eglDisplay, null, 0 /* majorOffset */, null, 1 /* minorOffset */)) { + err = "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + EGLConfig eglConfig = null; + int[] configsCount = new int[1]; + EGLConfig[] configs = new EGLConfig[1]; + int[] configSpec = new int[] { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_NONE + }; + + if (!eglChooseConfig(eglDisplay, configSpec, 0 /* attrib_listOffset */, + configs, 0 /* configOffset */, 1 /* config_size */, + configsCount, 0 /* num_configOffset */)) { + err = "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } else if (configsCount[0] > 0) { + eglConfig = configs[0]; + } + + if (eglConfig == null) { + throw new RuntimeException("eglConfig not initialized!"); + } + + int[] attr_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + EGLContext eglContext = eglCreateContext( + eglDisplay, eglConfig, EGL_NO_CONTEXT, attr_list, 0 /* offset */); + + if (eglContext == null || eglContext == EGL_NO_CONTEXT) { + err = "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + // We create a push buffer temporarily for querying info from GL. + int[] attrs = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + EGLSurface eglSurface = + eglCreatePbufferSurface(eglDisplay, eglConfig, attrs, 0 /* offset */); + eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + + // Now, we are ready to query the info from GL. + int[] maxSize = new int[1]; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0 /* offset */); + + // We have got the info we want, release all egl resources. + eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(eglDisplay, eglSurface); + eglDestroyContext(eglDisplay, eglContext); + eglTerminate(eglDisplay); + return maxSize[0]; + } catch (RuntimeException e) { + Log.w(TAG, "Retrieve from GL failed", e); + return Integer.MAX_VALUE; + } + } + + static int getMaxTextureSize() { + return sMaxTextureSize; + } +} + diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index b0f1e5d69be4..991c09a97bf5 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -134,6 +134,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private static final boolean DEBUG = false; private static final boolean DEBUG_LIVE = true; + // This 100MB limitation is defined in RecordingCanvas. + private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; + public static class Lifecycle extends SystemService { private IWallpaperManagerService mService; @@ -572,7 +575,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Only generate crop for default display. final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY); - Rect cropHint = new Rect(wallpaper.cropHint); + final Rect cropHint = new Rect(wallpaper.cropHint); + final DisplayInfo displayInfo = new DisplayInfo(); + mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); if (DEBUG) { Slog.v(TAG, "Generating crop for new wallpaper(s): 0x" @@ -618,12 +623,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } // scale if the crop height winds up not matching the recommended metrics - needScale = (wpData.mHeight != cropHint.height()); + needScale = wpData.mHeight != cropHint.height() + || cropHint.height() > GLHelper.getMaxTextureSize() + || cropHint.width() > GLHelper.getMaxTextureSize(); //make sure screen aspect ratio is preserved if width is scaled under screen size if (needScale) { - final DisplayInfo displayInfo = new DisplayInfo(); - mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height(); final int newWidth = (int) (cropHint.width() * scaleByHeight); if (newWidth < displayInfo.logicalWidth) { @@ -644,14 +649,29 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (!needCrop && !needScale) { // Simple case: the nominal crop fits what we want, so we take // the whole thing and just copy the image file directly. - if (DEBUG) { - Slog.v(TAG, "Null crop of new wallpaper; copying"); + + // TODO: It is not accurate to estimate bitmap size without decoding it, + // may be we can try to remove this optimized way in the future, + // that means, we will always go into the 'else' block. + + // This is just a quick estimation, may be smaller than it is. + long estimateSize = options.outWidth * options.outHeight * 4; + + // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. + // Please see: RecordingCanvas#throwIfCannotDraw. + if (estimateSize < MAX_BITMAP_SIZE) { + success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); } - success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); + if (!success) { wallpaper.cropFile.delete(); // TODO: fall back to default wallpaper in this case } + + if (DEBUG) { + Slog.v(TAG, "Null crop of new wallpaper, estimate size=" + + estimateSize + ", success=" + success); + } } else { // Fancy case: crop and scale. First, we decode and scale down if appropriate. FileOutputStream f = null; @@ -665,49 +685,78 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // We calculate the largest power-of-two under the actual ratio rather than // just let the decode take care of it because we also want to remap where the // cropHint rectangle lies in the decoded [super]rect. - final BitmapFactory.Options scaler; final int actualScale = cropHint.height() / wpData.mHeight; int scale = 1; - while (2*scale < actualScale) { + while (2 * scale <= actualScale) { scale *= 2; } - if (scale > 1) { - scaler = new BitmapFactory.Options(); - scaler.inSampleSize = scale; + options.inSampleSize = scale; + options.inJustDecodeBounds = false; + + final Rect estimateCrop = new Rect(cropHint); + estimateCrop.scale(1f / options.inSampleSize); + final float hRatio = (float) wpData.mHeight / estimateCrop.height(); + final int destHeight = (int) (estimateCrop.height() * hRatio); + final int destWidth = (int) (estimateCrop.width() * hRatio); + + // We estimated an invalid crop, try to adjust the cropHint to get a valid one. + if (destWidth > GLHelper.getMaxTextureSize()) { + int newHeight = (int) (wpData.mHeight / hRatio); + int newWidth = (int) (wpData.mWidth / hRatio); + if (DEBUG) { - Slog.v(TAG, "Downsampling cropped rect with scale " + scale); + Slog.v(TAG, "Invalid crop dimensions, trying to adjust."); } - } else { - scaler = null; + + estimateCrop.set(cropHint); + estimateCrop.left += (cropHint.width() - newWidth) / 2; + estimateCrop.top += (cropHint.height() - newHeight) / 2; + estimateCrop.right = estimateCrop.left + newWidth; + estimateCrop.bottom = estimateCrop.top + newHeight; + cropHint.set(estimateCrop); + estimateCrop.scale(1f / options.inSampleSize); + } + + // We've got the safe cropHint; now we want to scale it properly to + // the desired rectangle. + // That's a height-biased operation: make it fit the hinted height. + final int safeHeight = (int) (estimateCrop.height() * hRatio); + final int safeWidth = (int) (estimateCrop.width() * hRatio); + + if (DEBUG) { + Slog.v(TAG, "Decode parameters:"); + Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop); + Slog.v(TAG, " down sampling=" + options.inSampleSize + + ", hRatio=" + hRatio); + Slog.v(TAG, " dest=" + destWidth + "x" + destHeight); + Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight); + Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize()); } - Bitmap cropped = decoder.decodeRegion(cropHint, scaler); + + Bitmap cropped = decoder.decodeRegion(cropHint, options); decoder.recycle(); if (cropped == null) { Slog.e(TAG, "Could not decode new wallpaper"); } else { - // We've got the extracted crop; now we want to scale it properly to - // the desired rectangle. That's a height-biased operation: make it - // fit the hinted height, and accept whatever width we end up with. - cropHint.offsetTo(0, 0); - cropHint.right /= scale; // adjust by downsampling factor - cropHint.bottom /= scale; - final float heightR = - ((float) wpData.mHeight) / ((float) cropHint.height()); - if (DEBUG) { - Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint); - } - final int destWidth = (int)(cropHint.width() * heightR); + // We are safe to create final crop with safe dimensions now. final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, - destWidth, wpData.mHeight, true); + safeWidth, safeHeight, true); if (DEBUG) { Slog.v(TAG, "Final extract:"); Slog.v(TAG, " dims: w=" + wpData.mWidth + " h=" + wpData.mHeight); - Slog.v(TAG, " out: w=" + finalCrop.getWidth() + Slog.v(TAG, " out: w=" + finalCrop.getWidth() + " h=" + finalCrop.getHeight()); } + // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. + // Please see: RecordingCanvas#throwIfCannotDraw. + if (finalCrop.getByteCount() > MAX_BITMAP_SIZE) { + throw new RuntimeException( + "Too large bitmap, limit=" + MAX_BITMAP_SIZE); + } + f = new FileOutputStream(wallpaper.cropFile); bos = new BufferedOutputStream(f, 32*1024); finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos); @@ -1981,6 +2030,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (!isWallpaperSupported(callingPackage)) { return; } + + // Make sure both width and height are not larger than max texture size. + width = Math.min(width, GLHelper.getMaxTextureSize()); + height = Math.min(height, GLHelper.getMaxTextureSize()); + synchronized (mLock) { int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); |