diff --git a/Android.bp b/Android.bp index 21552695d7bd..eab3eb82cbdf 100644 --- a/Android.bp +++ b/Android.bp @@ -245,7 +245,7 @@ filegroup { ":libcamera_client_framework_aidl", ":libupdate_engine_aidl", // TODO: this needs to be removed when statsd-framework.jar is separated out - ":statsd_aidl", + ":statsd_java_aidl", ":storaged_aidl", ":vold_aidl", diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp index e6ca544c04be..aed6ad9fc08a 100644 --- a/apex/statsd/aidl/Android.bp +++ b/apex/statsd/aidl/Android.bp @@ -17,6 +17,18 @@ // TODO(b/145815909): move StatsDimensionsValue.aidl and StatsLogEventWrapper.aidl here filegroup { name: "statsd_aidl", + srcs: [ + "android/os/IPullAtomCallback.aidl", + "android/os/IPullAtomResultReceiver.aidl", + "android/os/IStatsCompanionService.aidl", + "android/os/IStatsd.aidl", + "android/os/IStatsPullerCallback.aidl", + "android/util/StatsEventParcel.aidl", + ], +} + +filegroup { + name: "statsd_java_aidl", srcs: ["**/*.aidl"], } diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl new file mode 100644 index 000000000000..45ba3a21ed5b --- /dev/null +++ b/apex/statsd/aidl/android/os/IStatsManagerService.aidl @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2019, 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 android.os; + +import android.app.PendingIntent; + +/** + * Binder interface to communicate with the Java-based statistics service helper. + * Contains parcelable objects available only in Java. + * {@hide} + */ +interface IStatsManagerService { + + /** + * Registers the given pending intent for this config key. This intent is invoked when the + * memory consumed by the metrics for this configuration approach the pre-defined limits. There + * can be at most one listener per config key. + * + * Requires Manifest.permission.DUMP. + */ + void setDataFetchOperation(long configKey, in PendingIntent pendingIntent, + in String packageName); + + /** + * Registers the given pending intent for this packagename. This intent is invoked when the + * active status of any of the configs sent by this package changes and will contain a list of + * config ids that are currently active. It also returns the list of configs that are currently + * active. There can be at most one active configs changed listener per package. + * + * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS. + */ + long[] setActiveConfigsChangedOperation(in PendingIntent pendingIntent, in String packageName); + + /** + * Set the PendingIntent to be used when broadcasting subscriber + * information to the given subscriberId within the given config. + * + * Suppose that the calling uid has added a config with key configKey, and that in this config + * it is specified that when a particular anomaly is detected, a broadcast should be sent to + * a BroadcastSubscriber with id subscriberId. This function links the given pendingIntent with + * that subscriberId (for that config), so that this pendingIntent is used to send the broadcast + * when the anomaly is detected. + * + * This function can only be called by the owner (uid) of the config. It must be called each + * time statsd starts. Later calls overwrite previous calls; only one PendingIntent is stored. + * + * Requires Manifest.permission.DUMP. + */ + void setBroadcastSubscriber(long configKey, long subscriberId, in PendingIntent pendingIntent, + in String packageName); +} \ No newline at end of file diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java new file mode 100644 index 000000000000..71b52e26b7db --- /dev/null +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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.stats; + +import android.content.Context; +import android.util.Slog; + +import com.android.server.SystemService; + +/** + * @hide + */ +public class StatsCompanion { + private static final String TAG = "StatsCompanion"; + private static final boolean DEBUG = false; + + /** + * Lifecycle class for both {@link StatsCompanionService} and {@link StatsManagerService}. + */ + public static final class Lifecycle extends SystemService { + private StatsCompanionService mStatsCompanionService; + private StatsManagerService mStatsManagerService; + + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mStatsCompanionService = new StatsCompanionService(getContext()); + mStatsManagerService = new StatsManagerService(getContext()); + mStatsCompanionService.setStatsManagerService(mStatsManagerService); + mStatsManagerService.setStatsCompanionService(mStatsCompanionService); + + try { + publishBinderService(Context.STATS_COMPANION_SERVICE, + mStatsCompanionService); + if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE); + publishBinderService(Context.STATS_MANAGER_SERVICE, + mStatsManagerService); + if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_MANAGER_SERVICE); + } catch (Exception e) { + Slog.e(TAG, "Failed to publishBinderService", e); + } + } + + @Override + public void onBootPhase(int phase) { + super.onBootPhase(phase); + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + mStatsCompanionService.systemReady(); + mStatsManagerService.systemReady(); + } + } + } +} diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index bc7716e5f6eb..157da636397e 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -137,7 +137,6 @@ import com.android.internal.os.StoragedUidIoStatsReader; import com.android.internal.util.DumpUtils; import com.android.server.BinderCallsStatsService; import com.android.server.LocalServices; -import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; import com.android.server.notification.NotificationManagerService; @@ -278,6 +277,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final BroadcastReceiver mUserUpdateReceiver; private final ShutdownEventReceiver mShutdownEventReceiver; + private StatsManagerService mStatsManagerService; + private static final class PullerKey { private final int mUid; private final int mAtomTag; @@ -2681,6 +2682,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { Slog.d(TAG, "learned that statsdReady"); } sayHiToStatsd(); // tell statsd that we're ready too and link to it + mStatsManagerService.systemReady(); mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED) .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND), UserHandle.SYSTEM, android.Manifest.permission.DUMP); @@ -2736,7 +2738,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - // Lifecycle and related code + // Statsd related code /** * Fetches the statsd IBinder service. @@ -2747,42 +2749,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { return IStatsd.Stub.asInterface(ServiceManager.getService("stats")); } - public static final class Lifecycle extends SystemService { - private StatsCompanionService mStatsCompanionService; - - public Lifecycle(Context context) { - super(context); - } - - @Override - public void onStart() { - mStatsCompanionService = new StatsCompanionService(getContext()); - try { - publishBinderService(Context.STATS_COMPANION_SERVICE, - mStatsCompanionService); - if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE); - } catch (Exception e) { - Slog.e(TAG, "Failed to publishBinderService", e); - } - } - - @Override - public void onBootPhase(int phase) { - super.onBootPhase(phase); - if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { - mStatsCompanionService.systemReady(); - } - } - } - /** * Now that the android system is ready, StatsCompanion is ready too, so inform statsd. */ - private void systemReady() { + void systemReady() { if (DEBUG) Slog.d(TAG, "Learned that systemReady"); sayHiToStatsd(); } + void setStatsManagerService(StatsManagerService statsManagerService) { + mStatsManagerService = statsManagerService; + } + /** * Tells statsd that statscompanion is ready. If the binder call returns, link to * statsd. diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java new file mode 100644 index 000000000000..f3bf9099c893 --- /dev/null +++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019 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.stats; + +import android.app.PendingIntent; +import android.content.Context; +import android.os.IBinder; +import android.os.IStatsManagerService; +import android.os.IStatsd; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +/** + * @hide + */ +public class StatsManagerService extends IStatsManagerService.Stub { + + private static final String TAG = "StatsManagerService"; + private static final boolean DEBUG = false; + + @GuardedBy("sStatsdLock") + private static IStatsd sStatsd; + private static final Object sStatsdLock = new Object(); + + private StatsCompanionService mStatsCompanionService; + + public StatsManagerService(Context context) { + super(); + } + + @Override + public void setDataFetchOperation(long configKey, PendingIntent pendingIntent, + String packageName) { + // no-op + if (DEBUG) { + Slog.d(TAG, "setDataFetchOperation"); + } + } + + @Override + public long[] setActiveConfigsChangedOperation(PendingIntent pendingIntent, + String packageName) { + // no-op + if (DEBUG) { + Slog.d(TAG, "setActiveConfigsChangedOperation"); + } + return new long[]{}; + } + + @Override + public void setBroadcastSubscriber(long configKey, long subscriberId, + PendingIntent pendingIntent, String packageName) { + //no-op + if (DEBUG) { + Slog.d(TAG, "setBroadcastSubscriber"); + } + } + + void setStatsCompanionService(StatsCompanionService statsCompanionService) { + mStatsCompanionService = statsCompanionService; + } + + void systemReady() { + if (DEBUG) { + Slog.d(TAG, "statsdReady"); + } + setupStatsManagerService(); + } + + private void setupStatsManagerService() { + synchronized (sStatsdLock) { + if (sStatsd != null) { + if (DEBUG) { + Slog.e(TAG, "Trying to fetch statsd, but it was already fetched", + new IllegalStateException( + "sStatsd is not null when being fetched")); + } + return; + } + sStatsd = IStatsd.Stub.asInterface(ServiceManager.getService("stats")); + // Assume statsd is ready since this is called form statscompanion, link to statsd. + try { + sStatsd.asBinder().linkToDeath((IBinder.DeathRecipient) () -> { + sStatsd = null; + }, 0); + } catch (RemoteException e) { + Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e); + } + } + } +} diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index f6e9569f513c..cd855cf134d9 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -27,6 +27,7 @@ import android.os.IBinder; import android.os.IPullAtomCallback; import android.os.IPullAtomResultReceiver; import android.os.IStatsCompanionService; +import android.os.IStatsManagerService; import android.os.IStatsPullerCallback; import android.os.IStatsd; import android.os.RemoteException; @@ -61,6 +62,9 @@ public final class StatsManager { @GuardedBy("sLock") private IStatsCompanionService mStatsCompanion; + @GuardedBy("sLock") + private IStatsManagerService mStatsManagerService; + /** * Long extra of uid that added the relevant stats config. */ @@ -686,6 +690,16 @@ public final class StatsManager { return mStatsCompanion; } + @GuardedBy("sLock") + private IStatsManagerService getIStatsManagerServiceLocked() { + if (mStatsManagerService != null) { + return mStatsManagerService; + } + mStatsManagerService = IStatsManagerService.Stub.asInterface( + ServiceManager.getService(Context.STATS_MANAGER_SERVICE)); + return mStatsManagerService; + } + /** * Exception thrown when communication with the stats service fails (eg if it is not available). * This might be thrown early during boot before the stats service has started or if it crashed. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d0844491da53..55a3d34cfeed 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4802,6 +4802,12 @@ public abstract class Context { */ public static final String INCIDENT_COMPANION_SERVICE = "incidentcompanion"; + /** + * Service to assist {@link android.app.StatsManager} that lives in system server. + * @hide + */ + public static final String STATS_MANAGER_SERVICE = "statsmanager"; + /** * Service to assist statsd in obtaining general stats. * @hide diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 7d6b0c99c5b5..b1ec3b4ba9a8 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -209,8 +209,8 @@ public final class SystemServer { "com.android.server.print.PrintManagerService"; private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS = "com.android.server.companion.CompanionDeviceManagerService"; - private static final String STATS_COMPANION_SERVICE_LIFECYCLE_CLASS = - "com.android.server.stats.StatsCompanionService$Lifecycle"; + private static final String STATS_COMPANION_LIFECYCLE_CLASS = + "com.android.server.stats.StatsCompanion$Lifecycle"; private static final String USB_SERVICE_CLASS = "com.android.server.usb.UsbService$Lifecycle"; private static final String MIDI_SERVICE_CLASS = @@ -1955,8 +1955,8 @@ public final class SystemServer { } // Statsd helper - t.traceBegin("StartStatsCompanionService"); - mSystemServiceManager.startService(STATS_COMPANION_SERVICE_LIFECYCLE_CLASS); + t.traceBegin("StartStatsCompanion"); + mSystemServiceManager.startService(STATS_COMPANION_LIFECYCLE_CLASS); t.traceEnd(); // Incidentd and dumpstated helper