diff options
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 { |