Loading services/core/java/com/android/server/am/ActivityManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -3635,7 +3635,8 @@ public final class ActivityManagerService extends ActivityManagerNative 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.isApp(procUid) || !UserHandle.isSameUser(procUid, uid) || UserHandle.isIsolated(procUid)) { // Don't use an app process or different user process for system component. continue; } Loading services/core/java/com/android/server/pm/PackageInstallerService.java +1 −0 Original line number Diff line number Diff line Loading @@ -591,6 +591,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { params.installFlags &= ~PackageManager.INSTALL_FROM_ADB; params.installFlags &= ~PackageManager.INSTALL_ALL_USERS; params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST; params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; } Loading services/core/java/com/android/server/wallpaper/GLHelper.java 0 → 100644 +148 −0 Original line number Diff line number Diff line /* * 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; } } services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +82 −26 Original line number Diff line number Diff line Loading @@ -115,6 +115,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { static final String TAG = "WallpaperManagerService"; static final boolean DEBUG = false; // This 100MB limitation is defined in DisplayListCanvas. private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; public static class Lifecycle extends SystemService { private WallpaperManagerService mService; Loading Loading @@ -368,7 +371,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } // scale if the crop height winds up not matching the recommended metrics needScale = (wallpaper.height != cropHint.height()); // also take care of invalid dimensions. needScale = wallpaper.height != cropHint.height() || cropHint.height() > GLHelper.getMaxTextureSize() || cropHint.width() > GLHelper.getMaxTextureSize(); if (DEBUG) { Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height()); Loading @@ -380,14 +386,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: DisplayListCanvas#throwIfCannotDraw. if (estimateSize < MAX_BITMAP_SIZE) { 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; Loading @@ -401,40 +422,63 @@ 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() / wallpaper.height; 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) wallpaper.height / 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) (wallpaper.height / hRatio); int newWidth = (int) (wallpaper.width / 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); } Bitmap cropped = decoder.decodeRegion(cropHint, scaler); // 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, 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)wallpaper.height) / ((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, wallpaper.height, true); safeWidth, safeHeight, true); if (DEBUG) { Slog.v(TAG, "Final extract:"); Slog.v(TAG, " dims: w=" + wallpaper.width Loading @@ -443,6 +487,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { + " h=" + finalCrop.getHeight()); } // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. // Please see: DisplayListCanvas#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); Loading Loading @@ -1234,6 +1285,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); Loading Loading
services/core/java/com/android/server/am/ActivityManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -3635,7 +3635,8 @@ public final class ActivityManagerService extends ActivityManagerNative 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.isApp(procUid) || !UserHandle.isSameUser(procUid, uid) || UserHandle.isIsolated(procUid)) { // Don't use an app process or different user process for system component. continue; } Loading
services/core/java/com/android/server/pm/PackageInstallerService.java +1 −0 Original line number Diff line number Diff line Loading @@ -591,6 +591,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { params.installFlags &= ~PackageManager.INSTALL_FROM_ADB; params.installFlags &= ~PackageManager.INSTALL_ALL_USERS; params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST; params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; } Loading
services/core/java/com/android/server/wallpaper/GLHelper.java 0 → 100644 +148 −0 Original line number Diff line number Diff line /* * 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; } }
services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +82 −26 Original line number Diff line number Diff line Loading @@ -115,6 +115,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { static final String TAG = "WallpaperManagerService"; static final boolean DEBUG = false; // This 100MB limitation is defined in DisplayListCanvas. private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; public static class Lifecycle extends SystemService { private WallpaperManagerService mService; Loading Loading @@ -368,7 +371,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } // scale if the crop height winds up not matching the recommended metrics needScale = (wallpaper.height != cropHint.height()); // also take care of invalid dimensions. needScale = wallpaper.height != cropHint.height() || cropHint.height() > GLHelper.getMaxTextureSize() || cropHint.width() > GLHelper.getMaxTextureSize(); if (DEBUG) { Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height()); Loading @@ -380,14 +386,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: DisplayListCanvas#throwIfCannotDraw. if (estimateSize < MAX_BITMAP_SIZE) { 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; Loading @@ -401,40 +422,63 @@ 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() / wallpaper.height; 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) wallpaper.height / 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) (wallpaper.height / hRatio); int newWidth = (int) (wallpaper.width / 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); } Bitmap cropped = decoder.decodeRegion(cropHint, scaler); // 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, 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)wallpaper.height) / ((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, wallpaper.height, true); safeWidth, safeHeight, true); if (DEBUG) { Slog.v(TAG, "Final extract:"); Slog.v(TAG, " dims: w=" + wallpaper.width Loading @@ -443,6 +487,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { + " h=" + finalCrop.getHeight()); } // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. // Please see: DisplayListCanvas#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); Loading Loading @@ -1234,6 +1285,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); Loading