1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.telemetry.publisher; 18 19 import android.annotation.NonNull; 20 import android.app.StatsManager; 21 import android.app.usage.NetworkStatsManager; 22 import android.car.telemetry.TelemetryProto; 23 import android.content.Context; 24 import android.os.Handler; 25 26 import com.android.car.CarPropertyService; 27 import com.android.car.telemetry.ResultStore; 28 import com.android.car.telemetry.UidPackageMapper; 29 import com.android.car.telemetry.publisher.net.NetworkStatsManagerProxy; 30 import com.android.car.telemetry.sessioncontroller.SessionController; 31 import com.android.internal.util.Preconditions; 32 33 import java.util.Objects; 34 35 /** 36 * Lazy factory class for Publishers. It's expected to have a single factory instance. Must be 37 * called from the telemetry thread. 38 * 39 * <p>It doesn't instantiate all the publishers right away, as in some cases some publishers are not 40 * needed. 41 * 42 * <p>Methods in this class must be called on telemetry thread unless specified as thread-safe. 43 */ 44 public class PublisherFactory { 45 // Some publishers must be initialized as early as possible during boot. 46 private static final TelemetryProto.Publisher.PublisherCase[] sForceInitPublishers = { 47 TelemetryProto.Publisher.PublisherCase.CONNECTIVITY 48 }; 49 50 private final Object mLock = new Object(); 51 private final CarPropertyService mCarPropertyService; 52 private final Handler mTelemetryHandler; 53 private final Context mContext; // CarService context 54 private final UidPackageMapper mUidMapper; 55 56 private VehiclePropertyPublisher mVehiclePropertyPublisher; 57 private CarTelemetrydPublisher mCarTelemetrydPublisher; 58 private StatsPublisher mStatsPublisher; 59 private ConnectivityPublisher mConnectivityPublisher; 60 private MemoryPublisher mMemoryPublisher; 61 private AbstractPublisher.PublisherListener mPublisherListener; 62 // To enable publishers to subscribe to session updates if needed. 63 private final SessionController mSessionController; 64 // To enable publishers to store pulled data in the event of suspend-to-RAM or shutdown. 65 private final ResultStore mResultStore; 66 PublisherFactory( @onNull CarPropertyService carPropertyService, @NonNull Handler handler, @NonNull Context context, @NonNull SessionController sessionController, @NonNull ResultStore resultStore, @NonNull UidPackageMapper uidMapper)67 public PublisherFactory( 68 @NonNull CarPropertyService carPropertyService, 69 @NonNull Handler handler, 70 @NonNull Context context, 71 @NonNull SessionController sessionController, 72 @NonNull ResultStore resultStore, 73 @NonNull UidPackageMapper uidMapper) { 74 mCarPropertyService = carPropertyService; 75 mTelemetryHandler = handler; 76 mContext = context; 77 mSessionController = sessionController; 78 mResultStore = resultStore; 79 mUidMapper = uidMapper; 80 } 81 82 /** Returns the publisher by given type. This method is thread-safe. */ 83 @NonNull getPublisher(@onNull TelemetryProto.Publisher.PublisherCase type)84 public AbstractPublisher getPublisher(@NonNull TelemetryProto.Publisher.PublisherCase type) { 85 Preconditions.checkState(mPublisherListener != null, "PublisherFactory is not initialized"); 86 // No need to optimize locks, as this method is infrequently called. 87 synchronized (mLock) { 88 switch (type.getNumber()) { 89 case TelemetryProto.Publisher.VEHICLE_PROPERTY_FIELD_NUMBER: 90 if (mVehiclePropertyPublisher == null) { 91 mVehiclePropertyPublisher = new VehiclePropertyPublisher( 92 mCarPropertyService, mPublisherListener, mTelemetryHandler); 93 } 94 return mVehiclePropertyPublisher; 95 case TelemetryProto.Publisher.CARTELEMETRYD_FIELD_NUMBER: 96 if (mCarTelemetrydPublisher == null) { 97 mCarTelemetrydPublisher = new CarTelemetrydPublisher( 98 mPublisherListener, mTelemetryHandler, mSessionController); 99 } 100 return mCarTelemetrydPublisher; 101 case TelemetryProto.Publisher.STATS_FIELD_NUMBER: 102 if (mStatsPublisher == null) { 103 StatsManager stats = mContext.getSystemService(StatsManager.class); 104 Preconditions.checkState(stats != null, "StatsManager not found"); 105 StatsManagerProxy statsManager = new StatsManagerImpl(stats); 106 mStatsPublisher = new StatsPublisher( 107 mPublisherListener, statsManager, mResultStore, mTelemetryHandler); 108 } 109 return mStatsPublisher; 110 case TelemetryProto.Publisher.CONNECTIVITY_FIELD_NUMBER: 111 if (mConnectivityPublisher == null) { 112 NetworkStatsManager networkStatsManager = 113 Objects.requireNonNull( 114 mContext.getSystemService(NetworkStatsManager.class)); 115 mConnectivityPublisher = 116 new ConnectivityPublisher( 117 mPublisherListener, 118 new NetworkStatsManagerProxy(networkStatsManager), 119 mTelemetryHandler, mResultStore, mSessionController, 120 mUidMapper); 121 } 122 return mConnectivityPublisher; 123 case TelemetryProto.Publisher.MEMORY_FIELD_NUMBER: 124 if (mMemoryPublisher == null) { 125 mMemoryPublisher = new MemoryPublisher( 126 mContext, mPublisherListener, mTelemetryHandler, mResultStore, 127 mSessionController); 128 } 129 return mMemoryPublisher; 130 default: 131 throw new IllegalArgumentException( 132 "Publisher type " + type + " is not supported"); 133 } 134 } 135 } 136 137 /** 138 * Removes all {@link com.android.car.telemetry.databroker.DataSubscriber} from all publishers. 139 */ removeAllDataSubscribers()140 public void removeAllDataSubscribers() { 141 if (mVehiclePropertyPublisher != null) { 142 mVehiclePropertyPublisher.removeAllDataSubscribers(); 143 } 144 if (mCarTelemetrydPublisher != null) { 145 mCarTelemetrydPublisher.removeAllDataSubscribers(); 146 } 147 if (mStatsPublisher != null) { 148 mStatsPublisher.removeAllDataSubscribers(); 149 } 150 if (mMemoryPublisher != null) { 151 mMemoryPublisher.removeAllDataSubscribers(); 152 } 153 } 154 155 /** 156 * Initializes the factory and sets the publisher listener for all the publishers. 157 * This is expected to be called before {@link #getPublisher} method. This is not the best 158 * approach, but it suits for this case. 159 */ initialize(@onNull AbstractPublisher.PublisherListener listener)160 public void initialize(@NonNull AbstractPublisher.PublisherListener listener) { 161 Preconditions.checkState( 162 mPublisherListener == null, "PublisherFactory is already initialized"); 163 mPublisherListener = listener; 164 for (TelemetryProto.Publisher.PublisherCase publisher : sForceInitPublishers) { 165 getPublisher(publisher); 166 } 167 } 168 } 169