Decouple package manager lock and bitmap decoding
Also moves the actual reading and decoding of the
icon into the client process to avoid unnecessary
copies.
Bug: 18474438
Change-Id: I71623ef48c770d752593aa97d69517f6139cc947
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 69a1ac9..dbfd7c7 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -28,7 +28,6 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -36,6 +35,7 @@
import android.os.Handler;
import android.os.IUserManager;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -111,6 +111,7 @@
private static final String USER_INFO_DIR = "system" + File.separator + "users";
private static final String USER_LIST_FILENAME = "userlist.xml";
private static final String USER_PHOTO_FILENAME = "photo.png";
+ private static final String USER_PHOTO_FILENAME_TMP = USER_PHOTO_FILENAME + ".tmp";
private static final String RESTRICTIONS_FILE_PREFIX = "res_";
private static final String XML_SUFFIX = ".xml";
@@ -433,7 +434,8 @@
}
@Override
- public Bitmap getUserIcon(int userId) {
+ public ParcelFileDescriptor getUserIcon(int userId) {
+ String iconPath;
synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
if (info == null || info.partial) {
@@ -448,8 +450,16 @@
if (info.iconPath == null) {
return null;
}
- return BitmapFactory.decodeFile(info.iconPath);
+ iconPath = info.iconPath;
}
+
+ try {
+ return ParcelFileDescriptor.open(
+ new File(iconPath), ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ Log.e(LOG_TAG, "Couldn't find icon file", e);
+ }
+ return null;
}
public void makeInitialized(int userId) {
@@ -572,6 +582,7 @@
try {
File dir = new File(mUsersDir, Integer.toString(info.id));
File file = new File(dir, USER_PHOTO_FILENAME);
+ File tmp = new File(dir, USER_PHOTO_FILENAME_TMP);
if (!dir.exists()) {
dir.mkdir();
FileUtils.setPermissions(
@@ -580,7 +591,8 @@
-1, -1);
}
FileOutputStream os;
- if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(file))) {
+ if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(tmp))
+ && tmp.renameTo(file)) {
info.iconPath = file.getAbsolutePath();
}
try {
@@ -588,6 +600,7 @@
} catch (IOException ioe) {
// What the ... !
}
+ tmp.delete();
} catch (FileNotFoundException e) {
Slog.w(LOG_TAG, "Error setting photo for user ", e);
}