1. 程式人生 > >MTK平臺CPU/GPU動態調頻的實現之PerfService的原始碼分析

MTK平臺CPU/GPU動態調頻的實現之PerfService的原始碼分析

Zygote程序啟動後會啟動System程序,在System程序啟動過程中會啟動系統中的關鍵服務,如AMS、PMS以及這裡要分析的PerfService。先看下流程圖:


SystemServer啟動PerfService服務是通過例項化PerfServiceImpl的物件perfService,並把該服務的Binder物件新增到ServiceManager中。

先看SystemServer類中的startOtherServices方法:

private void startOtherServices() {
    . . .
    PerfServiceStateNotifier perfServiceNotifier = null;
    IPerfServiceManager perfServiceMgr = null;
    . . .
    if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
        . . .
        /// M: add for PerfService feature @{
        if (SystemProperties.get("ro.mtk_perfservice_support").equals("1")) {
            try {
                Slog.i(TAG, "PerfService state notifier");
                // 例項化PerfService的狀態通知者
                perfServiceNotifier = new PerfServiceStateNotifier();
                // 把通知者註冊到AMS的觀察者中,有狀態變化時會通知所有註冊過的通知者
                mActivityManagerService.registerActivityStateNotifier(perfServiceNotifier);
            } catch (Throwable e) {
                Slog.e(TAG, "FAIL starting PerfServiceStateNotifier", e);
            }

            // Create PerfService manager thread and add service
            try {
                // 例項化PerfServiceManager執行緒
                perfServiceMgr = new PerfServiceManager(context);

                IPerfService perfService = null;
                // 例項化服務
                perfService = new PerfServiceImpl(context, perfServiceMgr);

                Slog.d("perfservice", "perfService=" + perfService);
                if (perfService != null) {
                    // 把服務新增到ServiceManager中
                    ServiceManager.addService(Context.MTK_PERF_SERVICE, perfService.asBinder());
                }

            } catch (Throwable e) {
                Slog.e(TAG, "perfservice Failure starting PerfService", e);
            }
        }
        /// @}
        . . .
    }
    . . .

    /// M: add for hdmi feature
    final IPerfServiceManager perfServiceF = perfServiceMgr;

    // We now tell the activity manager it is okay to run third party
    // code.  It will call back into us once it has gotten to the state
    // where third party code can really run (but before it has actually
    // started launching the initial applications), for us to complete our
    // initialization.
    mActivityManagerService.systemReady(new Runnable() {
        @Override
        public void run() {
            Slog.i(TAG, "Making services ready");
            . . .
            /// M: add for PerfService feature @{
            if (SystemProperties.get("ro.mtk_perfservice_support").equals("1")) {
                // Notify PerfService manager of system ready
                try {
                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakePerfServiceReady");
                    // 系統啟動後回撥IPerfServiceManager的systemReady方法
                    if (perfServiceF != null) perfServiceF.systemReady();
                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                } catch (Throwable e) {
                    reportWtf("making PerfServiceManager ready", e);
                }
            }
            /// @}
            . . .
        }
    });
    . . .
}
再看PerfServiceStateNotifier類,先看下它實現的介面IActivityStateNotifier:
public interface IActivityStateNotifier {

    public enum ActivityState {
        Paused,
        Resumed,
        Destroyed,
        Stopped
    }

    /**
     * Notify activity state change.
     *
     * @param packageName The target package name.
     * @param pid The process id package belongs to.
     * @param className The class name of the package.
     * @param actState Current lifecycle state of the package.
     */
    public void notifyActivityState(String packageName, int pid,
            String className, ActivityState actState);

    /**
     * Notify the process of activity has died.
     *
     * @param pid The process id has died.
     * @param packageList The whole packages runs on the process.
     */
    public void notifyAppDied(int pid, HashSet<String> packageList);
}

再看PerfServiceStateNotifier類的實現:
// 觀察者模式的使用
public final class PerfServiceStateNotifier implements IActivityStateNotifier {
    static final String TAG = "PerfServiceStateNotifier";

    IPerfServiceWrapper mPerfService;

    public PerfServiceStateNotifier() {
        // 例項化PerfServiceWrapper
        mPerfService = new PerfServiceWrapper(null);
    }
    /**
     * Notify activity state change
     * Activity狀態變化時回撥該方法
     */
    public void notifyActivityState(String packageName, int pid,
                                    String className, IActivityStateNotifier.ActivityState actState) {
        int state;
        //Slog.i(TAG,"[notifyActivityState] "+ packageName+ ", "+ className+ ", "+ actState);

        switch(actState) {
            case Paused:
                state = IPerfServiceWrapper.STATE_PAUSED;
                break;
            case Resumed:
                state = IPerfServiceWrapper.STATE_RESUMED;
                break;
            case Destroyed:
                state = IPerfServiceWrapper.STATE_DESTROYED;
                break;
            case Stopped:
                state = IPerfServiceWrapper.STATE_STOPPED;
                break;
            default:
                return;
        }
        // 呼叫mPerfService的狀態變化方法
        mPerfService.notifyAppState(packageName, className, state, pid);
    }

    /**
     * Notify the process of activity has died
     * Activity銷燬時回撥該方法
     */
    public void notifyAppDied(int pid, HashSet<String> packageList)
    {
        Iterator i = packageList.iterator();
        while (i.hasNext()) {
            String packageName = (String) i.next();
            // 呼叫mPerfService的狀態變化方法
            mPerfService.notifyAppState(packageName, null, IPerfServiceWrapper.STATE_DEAD, pid);
        }
    }

}

當所監聽的Activity生命週期方法被呼叫時會呼叫PerfServiceWrapper類的notifyAppState方法,那麼下面先看下PerfServiceWrapper實現的介面IPerfServiceWrapper:
public interface IPerfServiceWrapper {

	// 已經實現的場景
    public static final int SCN_NONE       = 0;
    public static final int SCN_APP_SWITCH = 1; /* apply for both launch/exit */ // 切換應用
    public static final int SCN_APP_ROTATE = 2; // 旋轉應用
    public static final int SCN_APP_TOUCH       = 3; // 觸控應用,即點選螢幕
    public static final int SCN_DONT_USE1       = 4; // 空閒???
    public static final int SCN_SW_FRAME_UPDATE = 5; // 重新整理幀率
    public static final int SCN_APP_LAUNCH      = 6; // 應用啟動  同SCN_APP_SWITCH
    public static final int SCN_GAMING          = 7; // 遊戲中。。。
    public static final int SCN_MAX             = 8; /* should be (last scenario + 1) */

    public static final int STATE_PAUSED    = 0;
    public static final int STATE_RESUMED   = 1;
    public static final int STATE_DESTROYED = 2;
    public static final int STATE_DEAD      = 3;
    public static final int STATE_STOPPED   = 4;

    public static final int DISPLAY_TYPE_GAME   = 0; // 遊戲模式顯示型別
    public static final int DISPLAY_TYPE_OTHERS = 1; // 非遊戲模式

    public static final int NOTIFY_USER_TYPE_PID = 0;
    public static final int NOTIFY_USER_TYPE_FRAME_UPDATE = 1;
    public static final int NOTIFY_USER_TYPE_DISPLAY_TYPE = 2;
    public static final int NOTIFY_USER_TYPE_SCENARIO_ON  = 3;
    public static final int NOTIFY_USER_TYPE_SCENARIO_OFF = 4;

    public static final int CMD_GET_CPU_FREQ_LEVEL_COUNT        = 0; // 獲取CPU頻率級別總數
    public static final int CMD_GET_CPU_FREQ_LITTLE_LEVEL_COUNT = 1; // 獲取小核CPU頻率級別總數
    public static final int CMD_GET_CPU_FREQ_BIG_LEVEL_COUNT    = 2; // 獲取大核CPU頻率級別總數
    public static final int CMD_GET_GPU_FREQ_LEVEL_COUNT        = 3; // 獲取GPU頻率級別總數
    public static final int CMD_GET_MEM_FREQ_LEVEL_COUNT        = 4; // 獲取記憶體頻率級別總數
    public static final int CMD_GET_PERF_INDEX_MIN              = 5; // 獲取效能優化最小索引值
    public static final int CMD_GET_PERF_INDEX_MAX              = 6; // 獲取效能優化最大索引值
    public static final int CMD_GET_PERF_NORMALIZED_INDEX_MAX   = 7; // 獲取普通效能優化最大索引值

    public static final int CMD_SET_CPU_CORE_MIN            = 0; // 設定CPU最少核數
    public static final int CMD_SET_CPU_CORE_MAX            = 1; // 設定CPU最多核數
    public static final int CMD_SET_CPU_CORE_BIG_LITTLE_MIN = 2; // 設定大核小核的最少核數
    public static final int CMD_SET_CPU_CORE_BIG_LITTLE_MAX = 3; // 設定大核小核的最多核數
    public static final int CMD_SET_CPU_FREQ_MIN            = 4; // 設定CPU的最低頻率值
    public static final int CMD_SET_CPU_FREQ_MAX            = 5; // 設定CPU的最高頻率值
    public static final int CMD_SET_CPU_FREQ_BIG_LITTLE_MIN = 6; // 設定大核小核的最低頻率值
    public static final int CMD_SET_CPU_FREQ_BIG_LITTLE_MAX = 7; // 設定大核小核的最高頻率值
    public static final int CMD_SET_GPU_FREQ_MIN            = 8; // 設定GPU的最低頻率值
    public static final int CMD_SET_GPU_FREQ_MAX            = 9; // 設定GPU的最高頻率值
    public static final int CMD_SET_VCORE                   = 10; // 設定圖形模式,0/2:預設模式,1:低功耗模式,3:高效能模式
    public static final int CMD_SET_SCREEN_OFF_STATE        = 11; // 設定鎖屏時狀態,0:鎖屏無效,1:鎖屏有效,2:鎖屏暫停,開屏恢復
    public static final int CMD_SET_CPUFREQ_HISPEED_FREQ    = 12; // 設定CPU高速頻率
    public static final int CMD_SET_CPUFREQ_MIN_SAMPLE_TIME = 13; // 設定取樣CPU頻率值的最小間隔時間
    public static final int CMD_SET_CPUFREQ_ABOVE_HISPEED_DELAY = 14; // 設定CPU超高速頻率延遲時間
    public static final int CMD_SET_CLUSTER_CPU_CORE_MIN    = 15; // 設定CPU簇的最少核數
    public static final int CMD_SET_CLUSTER_CPU_CORE_MAX    = 16; // 設定CPU簇的最多核數
    public static final int CMD_SET_CLUSTER_CPU_FREQ_MIN    = 17; // 設定CPU簇的最低頻率值
    public static final int CMD_SET_CLUSTER_CPU_FREQ_MAX    = 18; // 設定CPU簇的最高頻率值
    public static final int CMD_SET_ROOT_CLUSTER            = 19; // 設定root簇
    public static final int CMD_SET_CPU_UP_THRESHOLD        = 20; // 設定CPU溫度的最高閾值
    public static final int CMD_SET_CPU_DOWN_THRESHOLD      = 21; // 設定CPU溫度的最低閾值
    public static final int CMD_SET_PERF_INDEX              = 22; // 設定效能優化的索引值
    public static final int CMD_SET_NORMALIZED_PERF_INDEX   = 23; // 設定普通效能優化的索引值

	// 其他方法的宣告
    . . .
	
    public void notifyAppState(String packName, String className, int state, int pid);
	
	// 其他方法的宣告
    . . .
}

再看PerfServiceWrapper類的實現:
public class PerfServiceWrapper implements IPerfServiceWrapper {

    private static final String TAG = "PerfServiceWrapper";

    private IPerfService sService = null;
    private Context mContext;

    private int inited = 0;

    private int setTid = 0;
    private long mPreviousTime = 0;
    private static final int RENDER_THREAD_UPDATE_DURATION = 400;

    public static native int nativeGetPid();
    public static native int nativeGetTid();

    private void init() {
        if (inited == 0) {
            IBinder b = ServiceManager.checkService(Context.MTK_PERF_SERVICE);
            if (b != null) {
                // 獲取服務
                sService = IPerfService.Stub.asInterface(b);
                if (sService != null)
                    inited = 1;
                else
                    log("ERR: getService() sService is still null..");
            }
        }
    }

    public PerfServiceWrapper(Context context) {
        mContext = context;
        init();
    }
	
	// 其他介面中宣告方法的實現
	. . .

    public void notifyAppState(String packName, String className, int state, int pid) {
        //log("boostEnable");
        try {
            init();
            if (sService != null)
                // 呼叫sService的notifyAppState方法
                sService.notifyAppState(packName, className, state, pid);
        } catch (RemoteException e) {
            loge("ERR: RemoteException in notifyAppState:" + e);
        }
    }

	// 其他介面中宣告方法的實現
	. . .
	
    private void log(String info) {
        Log.d("@M_" + TAG, "[PerfServiceWrapper] " + info + " ");
    }

    private void loge(String info) {
        Log.e("@M_" + TAG, "[PerfServiceWrapper] ERR: " + info + " ");
    }
}

該類中的方法都是通過Binder程序間通訊方式呼叫PerfServiceImpl中的方法實現的。由下面分析知,最後呼叫的是PerfServiceManager中的方法。

下面看PerfServiceManager的例項化過程,該類實現了IPerfServiceManager介面:

public class PerfServiceManager implements IPerfServiceManager {
    private static final String TAG = "PerfServiceManager";
    private HandlerThread mHandlerThread;
    private PerfServiceThreadHandler mHandler;
    private Context mContext;
    final List<Integer> mTimeList;


    private boolean bDuringTouch;
    private boolean bRenderAwareValid; // render aware is only valid within 3 sec.渲染只在3秒內有效
    private static final int RENDER_AWARE_DURATION_MS = 3000;
    private static final int UI_UPDATE_DURATION_MS = 500;
    private static final int RENDER_BIT = 0x800000;
    private static final float HEAP_UTILIZATION_DURING_FRAME_UPDATE = 0.5f; // 重新整理幀時的堆疊利用率

    private int mDisplayType;
    private VMRuntime mRuntime;
    private float mDefaultUtilization;

    // 宣告的一些native方法,追蹤到native層後,MTK只提供了一個so庫,具體實現是看不到的。。。
    . . .
    public static native int nativePerfNotifyAppState(String packName, String className,
                                                      int state, int pid);
    // 宣告的一些native方法
    . . .

    public class PerfServiceAppState {
        private String mPackName;
        private String mClassName;
        private int mState;
        private int mPid;

        PerfServiceAppState(String packName, String className, int state, int pid) {
            mPackName = packName;
            mClassName = className;
            mState = state;
            mPid = pid;
        }
    }

    //static
    //{
    //    Log.w(TAG, "load libperfservice_jni.so");
    //    System.loadLibrary("perfservice_jni");
    //}

    public PerfServiceManager(Context context) {
        super();
        mContext = context;
        // 建立並開啟名為PerfServiceManager的執行緒
        mHandlerThread = new HandlerThread("PerfServiceManager", Process.THREAD_PRIORITY_FOREGROUND);
        mHandlerThread.start();
        Looper looper = mHandlerThread.getLooper();
        if (looper != null) {
            // 初始化Handler
            mHandler = new PerfServiceThreadHandler(looper);
        }
        mTimeList = new ArrayList<Integer>();
        bDuringTouch = false;
        bRenderAwareValid = false;
        // 預設顯示型別:非遊戲模式
        mDisplayType = IPerfServiceWrapper.DISPLAY_TYPE_OTHERS;
        mRuntime = VMRuntime.getRuntime();
        mDefaultUtilization = mRuntime.getTargetHeapUtilization();
        log("Created and started PerfService thread");
    }

    // 介面中其他方法的實現
    . . .

    public void notifyAppState(String packName, String className, int state, int pid) {
        //log("notifyAppState");
        Message msg = mHandler.obtainMessage();
        msg.what = PerfServiceThreadHandler.MESSAGE_NOTIFY_APP_STATE;
        msg.obj = new PerfServiceAppState(packName, className, state, pid);
        msg.sendToTarget();
    }
    . . .

    private class PerfServiceThreadHandler extends Handler {
        . . .
        private static final int MESSAGE_NOTIFY_APP_STATE        = 4;
        . . .

        public PerfServiceThreadHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            try {
                switch (msg.what) {
                    . . .
                    case MESSAGE_NOTIFY_APP_STATE:
                    {
                        PerfServiceAppState passedObject = (PerfServiceAppState) msg.obj;
                        //log("MESSAGE_NOTIFY_APP_STATE");
						// 通過呼叫native方法實現
                        nativePerfNotifyAppState(passedObject.mPackName, passedObject.mClassName,
                                passedObject.mState, passedObject.mPid);
                        passedObject = null;
                        msg.obj = null;
                        break;
                    }
                    . . .

                    default:
                    {
                        . . .
                    }
                }
            } catch (NullPointerException e) {
                loge("Exception in PerfServiceThreadHandler.handleMessage: " + e);
            }
        }
        . . .

    }

    private void log(String info) {
        Log.d("@M_" + TAG, "[PerfService] " + info + " ");
    }

    private void loge(String info) {
        Log.e("@M_" + TAG, "[PerfService] ERR: " + info + " ");
    }

}

再看PerfServiceImpl類的實現:
public class PerfServiceImpl extends IPerfService.Stub {

    private static final String TAG = "PerfService";

    private IPerfServiceManager perfServiceMgr;
    final   Context mContext;

    // 接收鎖屏/開屏的廣播
    class PerfServiceBroadcastReceiver extends android.content.BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                log("Intent.ACTION_SCREEN_OFF");
                perfServiceMgr.userDisableAll();
                return;
            }
            else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                log("Intent.ACTION_SCREEN_ON");
                perfServiceMgr.userRestoreAll();
                return;
            }
            else {
                log("Unexpected intent " + intent);
            }
        }
    }

    public PerfServiceImpl(Context context, IPerfServiceManager pm) {
        perfServiceMgr = pm;
        mContext = context;

        final IntentFilter broadcastFilter = new IntentFilter();
        broadcastFilter.addAction(Intent.ACTION_SCREEN_OFF);
        broadcastFilter.addAction(Intent.ACTION_SCREEN_ON);
        mContext.registerReceiver(new PerfServiceBroadcastReceiver(), broadcastFilter);

    }

    // aidl中宣告的其他方法
    . . .

    public void notifyAppState(java.lang.String packName, java.lang.String className,
                               int state, int pid) {
        //log("notifyAppState");
		// 呼叫PerfServiceManager中的方法,最後呼叫的是native方法
        perfServiceMgr.notifyAppState(packName, className, state, pid);
    }

    . . .

    private void log(String info) {
        Log.d("@M_" + TAG, "[PerfService] " + info + " ");
    }

    private void loge(String info) {
        Log.e("@M_" + TAG, "[PerfService] ERR: " + info + " ");
    }
}

另外:

在vendor\mediatek\proprietary\hardware\perfservice\mt**\app_list目錄下的perfservapplist.txt檔案中可以自定義應用白名單,預設值為:

CMD_SET_CPU_CORE_MIN com.imangi.templerun2 3

意思是使用者使用“神廟逃亡”應用時,CPU最少核心數為3

在vendor\mediatek\proprietary\hardware\perfservice\mt**\scn_tbl目錄下的perfservscntbl.txt檔案中可以自定義場景,預設場景有:

CMD_SET_CPU_CORE_MIN, SCN_APP_TOUCH, 3
CMD_SET_CPU_FREQ_MIN, SCN_APP_TOUCH, 1014000
CMD_SET_CPU_CORE_MIN, SCN_SW_FRAME_UPDATE, 3
CMD_SET_CPU_FREQ_MIN, SCN_SW_FRAME_UPDATE, 1014000
CMD_SET_CPU_UP_THRESHOLD, SCN_SW_FRAME_UPDATE, 80
CMD_SET_CPU_DOWN_THRESHOLD, SCN_SW_FRAME_UPDATE, 65
CMD_SET_CPU_FREQ_BIG_LITTLE_MIN, SCN_APP_SWITCH, 1950000, 1144000
CMD_SET_CPU_CORE_BIG_LITTLE_MIN, SCN_APP_SWITCH, 4, 0
CMD_SET_VCORE, SCN_APP_SWITCH, 3
CMD_SET_CPU_FREQ_BIG_LITTLE_MIN, SCN_APP_ROTATE, 1950000, 1144000
CMD_SET_VCORE, SCN_APP_ROTATE, 3
CMD_SET_VCORE, SCN_GAMING, 1