summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java10
-rw-r--r--services/core/java/com/android/server/pm/MultiTaskDealer.java141
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java112
4 files changed, 225 insertions, 44 deletions
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index f479f4f..f5b948f 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -62,6 +62,8 @@ public class NativeLibraryHelper {
// that the cpuAbiOverride must be clear.
public static final String CLEAR_ABI_OVERRIDE = "-";
+ private static final Object mRestoreconSync = new Object();
+
/**
* A handle to an opened package, consisting of one or more APKs. Used as
* input to the various NativeLibraryHelper methods. Allows us to scan and
@@ -275,8 +277,12 @@ public class NativeLibraryHelper {
throw new IOException("Cannot chmod native library directory "
+ path.getPath(), e);
}
- } else if (!SELinux.restorecon(path)) {
- throw new IOException("Cannot set SELinux context for " + path.getPath());
+ } else {
+ synchronized (mRestoreconSync) {
+ if (!SELinux.restorecon(path)) {
+ throw new IOException("Cannot set SELinux context for " + path.getPath());
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/MultiTaskDealer.java b/services/core/java/com/android/server/pm/MultiTaskDealer.java
new file mode 100644
index 0000000..9b8d46e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/MultiTaskDealer.java
@@ -0,0 +1,141 @@
+/*
+* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package com.android.server.pm;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+import android.util.Log;
+
+public class MultiTaskDealer {
+
+ public static final String TAG = "MultiTaskDealer";
+ public static final String PACKAGEMANAGER_SCANER = "packagescan";
+ private static final boolean DEBUG_TASK = false;
+
+ private static HashMap<String, WeakReference<MultiTaskDealer>> map = new HashMap<String, WeakReference<MultiTaskDealer>>();
+
+ public static MultiTaskDealer getDealer(String name) {
+ WeakReference<MultiTaskDealer> ref = map.get(name);
+ MultiTaskDealer dealer = ref!=null?ref.get():null;
+ return dealer;
+ }
+
+ public static MultiTaskDealer startDealer(String name,int taskCount) {
+ MultiTaskDealer dealer = getDealer(name);
+ if(dealer==null) {
+ dealer = new MultiTaskDealer(name,taskCount);
+ WeakReference<MultiTaskDealer> ref = new WeakReference<MultiTaskDealer>(dealer);
+ map.put(name,ref);
+ }
+ return dealer;
+ }
+
+ public void startLock() {
+ mLock.lock();
+ }
+
+ public void endLock() {
+ mLock.unlock();
+ }
+
+ private ThreadPoolExecutor mExecutor;
+ private int mTaskCount = 0;
+ private boolean mNeedNotifyEnd = false;
+ private Object mObjWaitAll = new Object();
+ private ReentrantLock mLock = new ReentrantLock();
+
+ public MultiTaskDealer(String name,int taskCount) {
+ final String taskName = name;
+ ThreadFactory factory = new ThreadFactory()
+ {
+ private final AtomicInteger mCount = new AtomicInteger(1);
+
+ public Thread newThread(final Runnable r) {
+ if (DEBUG_TASK) Log.d(TAG, "create a new thread:" + taskName);
+ return new Thread(r, taskName + "-" + mCount.getAndIncrement());
+ }
+ };
+ mExecutor = new ThreadPoolExecutor(taskCount, taskCount, 5, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>(), factory){
+ protected void afterExecute(Runnable r, Throwable t) {
+ if(t!=null) {
+ t.printStackTrace();
+ }
+ MultiTaskDealer.this.TaskCompleteNotify(r);
+ if (DEBUG_TASK) Log.d(TAG, "end task");
+ super.afterExecute(r,t);
+ }
+ protected void beforeExecute(Thread t, Runnable r) {
+ if (DEBUG_TASK) Log.d(TAG, "start task");
+ super.beforeExecute(t,r);
+ }
+ };
+ }
+
+ public void addTask(Runnable task) {
+ synchronized (mObjWaitAll) {
+ mTaskCount+=1;
+ }
+ mExecutor.execute(task);
+ if (DEBUG_TASK) Log.d(TAG, "addTask");
+ }
+
+ private void TaskCompleteNotify(Runnable task) {
+ synchronized (mObjWaitAll) {
+ mTaskCount-=1;
+ if(mTaskCount<=0 && mNeedNotifyEnd) {
+ if (DEBUG_TASK) Log.d(TAG, "complete notify");
+ mObjWaitAll.notify();
+ }
+ }
+ }
+
+ public void waitAll() {
+ if (DEBUG_TASK) Log.d(TAG, "start wait all");
+ synchronized (mObjWaitAll) {
+ if(mTaskCount>0) {
+ mNeedNotifyEnd = true;
+ try {
+ mObjWaitAll.wait();
+ } catch (Exception e) {
+ }
+ mNeedNotifyEnd = false;
+ }
+ if (DEBUG_TASK) Log.d(TAG, "wait finish");
+ return;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index f73cb0a..fa11ff8 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -57,6 +57,8 @@ final class PackageDexOptimizer {
private final PowerManager.WakeLock mDexoptWakeLock;
private volatile boolean mSystemReady;
+ private Object mDeferredDexOptSync = new Object();
+
PackageDexOptimizer(PackageManagerService packageManagerService) {
this.mPackageManagerService = packageManagerService;
PowerManager powerManager = (PowerManager)packageManagerService.mContext.getSystemService(
@@ -150,7 +152,9 @@ final class PackageDexOptimizer {
// We're deciding to defer a needed dexopt. Don't bother dexopting for other
// paths and instruction sets. We'll deal with them all together when we process
// our list of deferred dexopts.
- addPackageForDeferredDexopt(pkg);
+ synchronized (mDeferredDexOptSync) {
+ addPackageForDeferredDexopt(pkg);
+ }
return DEX_OPT_DEFERRED;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fc3d79c..fa085a2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2006 The Android Open Source Project
* This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
@@ -1974,9 +1977,9 @@ public class PackageManagerService extends IPackageManager.Stub {
mAvailableFeatures = systemConfig.getAvailableFeatures();
mSignatureAllowances = systemConfig.getSignatureAllowances();
- synchronized (mInstallLock) {
+// synchronized (mInstallLock) {
// writer
- synchronized (mPackages) {
+// synchronized (mPackages) {
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
@@ -2500,8 +2503,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mIntentFilterVerifier = new IntentVerifierProxy(mContext,
mIntentFilterVerifierComponent);
- } // synchronized (mPackages)
- } // synchronized (mInstallLock)
+ //} // synchronized (mPackages)
+ //} // synchronized (mInstallLock)
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
@@ -5827,7 +5830,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime,
- UserHandle user) {
+ final UserHandle user) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
@@ -5839,8 +5842,8 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " flags=0x" + Integer.toHexString(parseFlags));
}
- int prebundledUserId = user == null ? UserHandle.USER_OWNER : user.getIdentifier();
- boolean isPrebundled = (parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0;
+ final int prebundledUserId = user == null ? UserHandle.USER_OWNER : user.getIdentifier();
+ final boolean isPrebundled = (parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0;
if (isPrebundled) {
synchronized (mPackages) {
if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG, "Reading prebundled packages for user "
@@ -5849,6 +5852,13 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ Log.d(TAG, "start scanDirLI:"+dir);
+ // use multi thread to speed up scanning
+ int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask", 6);
+ Log.d(TAG, "max thread:" + iMultitaskNum);
+ final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
+ MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;
+
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
@@ -5856,46 +5866,64 @@ public class PackageManagerService extends IPackageManager.Stub {
// Ignore entries which are not packages
continue;
}
- try {
- scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
- scanFlags, currentTime, user);
- if (isPrebundled) {
- final PackageParser.Package pkg;
+
+ final File ref_file = file;
+ final int ref_parseFlags = parseFlags;
+ final int ref_scanFlags = scanFlags;
+ final long ref_currentTime = currentTime;
+
+ Runnable scanTask = new Runnable() {
+ public void run() {
+
try {
- pkg = new PackageParser().parsePackage(file, parseFlags);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
- }
- synchronized (mPackages) {
- if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG,
- "Marking prebundled package " + pkg.packageName +
- " for user " + prebundledUserId);
- mSettings.markPrebundledPackageInstalledLPr(prebundledUserId,
- pkg.packageName);
- // do this for every other user
- for (UserInfo userInfo : sUserManager.getUsers(true)) {
- if (userInfo.id == prebundledUserId) continue;
+ scanPackageLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK,
+ ref_scanFlags, ref_currentTime, user);
+ if (isPrebundled) {
+ final PackageParser.Package pkg;
+ try {
+ pkg = new PackageParser().parsePackage(ref_file, ref_parseFlags);
+ } catch (PackageParserException e) {
+ throw PackageManagerException.from(e);
+ }
if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG,
- "Marking for secondary user " + userInfo.id);
- mSettings.markPrebundledPackageInstalledLPr(userInfo.id,
+ "Marking prebundled package " + pkg.packageName +
+ " for user " + prebundledUserId);
+ mSettings.markPrebundledPackageInstalledLPr(prebundledUserId,
pkg.packageName);
+ // do this for every other user
+ for (UserInfo userInfo : sUserManager.getUsers(true)) {
+ if (userInfo.id == prebundledUserId) continue;
+ if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG,
+ "Marking for secondary user " + userInfo.id);
+ mSettings.markPrebundledPackageInstalledLPr(userInfo.id,
+ pkg.packageName);
+ }
+ }
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage());
+
+ // Delete invalid userdata apps
+ if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
+ e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
+ logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file);
+ if (ref_file.isDirectory()) {
+ mInstaller.rmPackageDir(ref_file.getAbsolutePath());
+ } else {
+ ref_file.delete();
+ }
}
}
}
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
+ };
- // Delete invalid userdata apps
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
- e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
- logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
- if (file.isDirectory()) {
- mInstaller.rmPackageDir(file.getAbsolutePath());
- } else {
- file.delete();
- }
- }
- }
+ if (dealer != null)
+ dealer.addTask(scanTask);
+ else
+ scanTask.run();
+ }
+
+ if (dealer != null) {
+ dealer.waitAll();
}
if (isPrebundled) {
@@ -5905,6 +5933,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.writePrebundledPackagesLPr(prebundledUserId);
}
}
+
+ Log.d(TAG, "end scanDirLI:"+dir);
}
private static File getSettingsProblemFile() {
@@ -5918,7 +5948,7 @@ public class PackageManagerService extends IPackageManager.Stub {
logCriticalInfo(priority, msg);
}
- static void logCriticalInfo(int priority, String msg) {
+ static synchronized void logCriticalInfo(int priority, String msg) {
Slog.println(priority, TAG, msg);
EventLogTags.writePmCriticalInfo(msg);
try {