Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5b0cb0d9 authored by qqzhou's avatar qqzhou Committed by Linux Build Service Account
Browse files

pm: Improve the scan process

Use multi task to speed up the scan process

Change-Id: Icbcb88c42e794c3b83037fa763c7f479a9df5bcb
CRs-Fixed: 984513
parent 5fce2f7e
Loading
Loading
Loading
Loading
+141 −0
Original line number Diff line number Diff line
/*
* 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;
        }
    }
}
+43 −16
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
 * Not a Contribution.
 *
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
@@ -2276,9 +2279,9 @@ public class PackageManagerService extends IPackageManager.Stub {
        mSystemPermissions = systemConfig.getSystemPermissions();
        mAvailableFeatures = systemConfig.getAvailableFeatures();
        synchronized (mInstallLock) {
//        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
//        synchronized (mPackages) {
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
@@ -2834,8 +2837,8 @@ public class PackageManagerService extends IPackageManager.Stub {
            }
            mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
        } // 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
@@ -6702,6 +6705,13 @@ public class PackageManagerService extends IPackageManager.Stub {
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }
        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());
@@ -6709,20 +6719,37 @@ public class PackageManagerService extends IPackageManager.Stub {
                // Ignore entries which are not packages
                continue;
            }
            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 {
                scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                        scanFlags, currentTime, null);
                        scanPackageTracedLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK,
                                ref_scanFlags, ref_currentTime, null);
                    } catch (PackageManagerException e) {
                Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
                        Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage());
                        // Delete invalid userdata apps
                if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                        if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                                e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                    logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                    removeCodePathLI(file);
                            logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file);
                            removeCodePathLI(ref_file);
                        }
                    }
                }
            };
            if (dealer != null)
                dealer.addTask(scanTask);
            else
                scanTask.run();
        }
        if (dealer != null)
            dealer.waitAll();
        Log.d(TAG, "end scanDirLI:"+dir);
    }
    private static File getSettingsProblemFile() {
@@ -6736,7 +6763,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 {