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

Commit 6b11cc83 authored by Yi Kong's avatar Yi Kong Committed by Android (Google) Code Review
Browse files

Merge "Introduce ProfcollectForwardingService"

parents 1750f5fe 86f85936
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ filegroup {
        ":services.midi-sources",
        ":services.net-sources",
        ":services.print-sources",
        ":services.profcollect-sources",
        ":services.restrictions-sources",
        ":services.startop.iorap-sources",
        ":services.systemcaptions-sources",
@@ -73,6 +74,7 @@ java_library {
        "services.net",
        "services.people",
        "services.print",
        "services.profcollect",
        "services.restrictions",
        "services.startop",
        "services.systemcaptions",
+7 −0
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ import com.android.server.policy.role.LegacyRoleResolutionPolicy;
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.power.ThermalManagerService;
import com.android.server.profcollect.ProfcollectForwardingService;
import com.android.server.recoverysystem.RecoverySystemService;
import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.role.RoleManagerService;
@@ -1229,6 +1230,12 @@ public final class SystemServer {
            mSystemServiceManager.startService(IorapForwardingService.class);
            t.traceEnd();

            if (Build.IS_DEBUGGABLE) {
                t.traceBegin("ProfcollectForwardingService");
                mSystemServiceManager.startService(ProfcollectForwardingService.class);
                t.traceEnd();
            }

            t.traceBegin("SignedConfigService");
            SignedConfigService.registerUpdateReceiver(mSystemContext);
            t.traceEnd();
+35 −0
Original line number Diff line number Diff line
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

filegroup {
  name: "services.profcollect-javasources",
  srcs: ["src/**/*.java"],
  path: "src",
  visibility: ["//frameworks/base/services"],
}

filegroup {
  name: "services.profcollect-sources",
  srcs: [
    ":services.profcollect-javasources",
    ":profcollectd_aidl",
  ],
  visibility: ["//frameworks/base/services:__subpackages__"],
}

java_library_static {
  name: "services.profcollect",
  srcs: [":services.profcollect-sources"],
  libs: ["services.core"],
}
+3 −0
Original line number Diff line number Diff line
srhines@google.com
yabinc@google.com
yikong@google.com
+196 −0
Original line number Diff line number Diff line
/**
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.profcollect;

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder.DeathRecipient;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.util.Log;

import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityMetricsLaunchObserver;
import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
import com.android.server.wm.ActivityTaskManagerInternal;

import java.util.concurrent.ThreadLocalRandom;

/**
 * System-server-local proxy into the {@code IProfcollectd} native service.
 */
public final class ProfcollectForwardingService extends SystemService {
    public static final String LOG_TAG = "ProfcollectForwardingService";

    private IProfCollectd mIProfcollect;
    private ProfcollectForwardingService mSelfService;
    private final Handler mHandler = new ProfcollectdHandler(IoThread.getHandler().getLooper());

    public ProfcollectForwardingService(Context context) {
        super(context);

        if (mSelfService != null) {
            throw new AssertionError("only one service instance allowed");
        }
        mSelfService = this;
    }

    @Override
    public void onStart() {
        Log.i(LOG_TAG, "Profcollect forwarding service start");
        connectNativeService();
        if (mIProfcollect == null) {
            return;
        }
        if (serviceHasSupportedTraceProvider()) {
            registerObservers();
        }
    }

    private boolean serviceHasSupportedTraceProvider() {
        if (mIProfcollect == null) {
            return false;
        }
        try {
            return !mIProfcollect.GetSupportedProvider().isEmpty();
        } catch (RemoteException e) {
            Log.e(LOG_TAG, e.getMessage());
            return false;
        }
    }

    private boolean tryConnectNativeService() {
        if (connectNativeService()) {
            return true;
        }
        // Cannot connect to the native service at this time, retry after a short delay.
        mHandler.sendEmptyMessageDelayed(ProfcollectdHandler.MESSAGE_BINDER_CONNECT, 5000);
        return false;
    }

    private boolean connectNativeService() {
        try {
            IProfCollectd profcollectd =
                    IProfCollectd.Stub.asInterface(
                            ServiceManager.getServiceOrThrow("profcollectd"));
            profcollectd.asBinder().linkToDeath(new ProfcollectdDeathRecipient(), /*flags*/0);
            mIProfcollect = profcollectd;
            return true;
        } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
            Log.w(LOG_TAG, "Failed to connect profcollectd binder service.");
            return false;
        }
    }

    private class ProfcollectdHandler extends Handler {
        public ProfcollectdHandler(Looper looper) {
            super(looper);
        }

        public static final int MESSAGE_BINDER_CONNECT = 0;

        @Override
        public void handleMessage(android.os.Message message) {
            switch (message.what) {
                case MESSAGE_BINDER_CONNECT:
                    connectNativeService();
                    break;
                default:
                    throw new AssertionError("Unknown message: " + message.toString());
            }
        }
    }

    private class ProfcollectdDeathRecipient implements DeathRecipient {
        @Override
        public void binderDied() {
            Log.w(LOG_TAG, "profcollectd has died");

            mIProfcollect = null;
            tryConnectNativeService();
        }
    }

    // Event observers
    private void registerObservers() {
        registerAppLaunchObserver();
    }

    private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver();
    private void registerAppLaunchObserver() {
        ActivityTaskManagerInternal atmInternal =
                LocalServices.getService(ActivityTaskManagerInternal.class);
        ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
                atmInternal.getLaunchObserverRegistry();
        launchObserverRegistry.registerLaunchObserver(mAppLaunchObserver);
    }

    private void traceOnAppStart(String packageName) {
        if (mIProfcollect == null) {
            return;
        }

        // Sample for a fraction of app launches.
        int traceFrequency = SystemProperties.getInt("profcollectd.applaunch_trace_freq", 2);
        int randomNum = ThreadLocalRandom.current().nextInt(100);
        if (randomNum < traceFrequency) {
            try {
                Log.i(LOG_TAG, "Tracing on app launch event: " + packageName);
                mIProfcollect.TraceOnce("applaunch");
            } catch (RemoteException e) {
                Log.e(LOG_TAG, e.getMessage());
            }
        }
    }

    private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
        @Override
        public void onIntentStarted(Intent intent, long timestampNanos) {
            traceOnAppStart(intent.getPackage());
        }

        @Override
        public void onIntentFailed() {
            // Ignored
        }

        @Override
        public void onActivityLaunched(byte[] activity, int temperature) {
            // Ignored
        }

        @Override
        public void onActivityLaunchCancelled(byte[] abortingActivity) {
            // Ignored
        }

        @Override
        public void onActivityLaunchFinished(byte[] finalActivity, long timestampNanos) {
            // Ignored
        }

        @Override
        public void onReportFullyDrawn(byte[] activity, long timestampNanos) {
            // Ignored
        }
    }
}