Merge "Cleanup threading in StatsCompanionService" into rvc-dev am: c7a08b57d4

Change-Id: I9c20959e7fedb2159b2943c5f4fb0ee85194b906
This commit is contained in:
Automerger Merge Worker
2020-03-10 21:08:39 +00:00

View File

@@ -54,6 +54,7 @@ import java.io.FileDescriptor;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -102,9 +103,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener(); private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
private final OnAlarmListener mPullingAlarmListener = new PullingAlarmListener(); private final OnAlarmListener mPullingAlarmListener = new PullingAlarmListener();
private final OnAlarmListener mPeriodicAlarmListener = new PeriodicAlarmListener(); private final OnAlarmListener mPeriodicAlarmListener = new PeriodicAlarmListener();
private final BroadcastReceiver mAppUpdateReceiver;
private final BroadcastReceiver mUserUpdateReceiver;
private final ShutdownEventReceiver mShutdownEventReceiver;
private StatsManagerService mStatsManagerService; private StatsManagerService mStatsManagerService;
@@ -118,27 +116,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
super(); super();
mContext = context; mContext = context;
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mAppUpdateReceiver = new AppUpdateReceiver();
mUserUpdateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (sStatsdLock) {
if (sStatsd == null) {
Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
return;
}
try {
// Pull the latest state of UID->app name, version mapping.
// Needed since the new user basically has a version of every app.
informAllUidsLocked(context);
} catch (RemoteException e) {
Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
forgetEverythingLocked();
}
}
}
};
mShutdownEventReceiver = new ShutdownEventReceiver();
if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED."); if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
HandlerThread handlerThread = new HandlerThread(TAG); HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start(); handlerThread.start();
@@ -162,9 +139,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
return ret; return ret;
} }
// Assumes that sStatsdLock is held. /**
@GuardedBy("sStatsdLock") * Non-blocking call to retrieve a reference to statsd
private void informAllUidsLocked(Context context) throws RemoteException { *
* @return IStatsd object if statsd is ready, null otherwise.
*/
private static IStatsd getStatsdNonblocking() {
synchronized (sStatsdLock) {
return sStatsd;
}
}
private static void informAllUidsLocked(Context context) throws RemoteException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
PackageManager pm = context.getPackageManager(); PackageManager pm = context.getPackageManager();
final List<UserHandle> users = um.getUserHandles(true); final List<UserHandle> users = um.getUserHandles(true);
@@ -273,7 +259,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (!replacing) { if (!replacing) {
// Don't bother sending an update if we're right about to get another // Don't bother sending an update if we're right about to get another
// intent for the new version that's added. // intent for the new version that's added.
PackageManager pm = context.getPackageManager();
String app = intent.getData().getSchemeSpecificPart(); String app = intent.getData().getSchemeSpecificPart();
sStatsd.informOnePackageRemoved(app, uid); sStatsd.informOnePackageRemoved(app, uid);
} }
@@ -303,23 +288,43 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
} }
} }
public final static class AnomalyAlarmListener implements OnAlarmListener { private static final class UserUpdateReceiver extends BroadcastReceiver {
@Override @Override
public void onAlarm() { public void onReceive(Context context, Intent intent) {
Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ System.currentTimeMillis() + "ms.");
synchronized (sStatsdLock) { synchronized (sStatsdLock) {
if (sStatsd == null) { if (sStatsd == null) {
Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
return; return;
} }
try { try {
// Two-way call to statsd to retain AlarmManager wakelock // Pull the latest state of UID->app name, version mapping.
sStatsd.informAnomalyAlarmFired(); // Needed since the new user basically has a version of every app.
informAllUidsLocked(context);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e); Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
} }
} }
}
}
public static final class AnomalyAlarmListener implements OnAlarmListener {
@Override
public void onAlarm() {
if (DEBUG) {
Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ System.currentTimeMillis() + "ms.");
}
IStatsd statsd = getStatsdNonblocking();
if (statsd == null) {
Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
return;
}
try {
// Two-way call to statsd to retain AlarmManager wakelock
statsd.informAnomalyAlarmFired();
} catch (RemoteException e) {
Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
}
// AlarmManager releases its own wakelock here. // AlarmManager releases its own wakelock here.
} }
} }
@@ -330,17 +335,16 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "Time to poll something."); Log.d(TAG, "Time to poll something.");
} }
synchronized (sStatsdLock) { IStatsd statsd = getStatsdNonblocking();
if (sStatsd == null) { if (statsd == null) {
Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing."); Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
return; return;
} }
try { try {
// Two-way call to statsd to retain AlarmManager wakelock // Two-way call to statsd to retain AlarmManager wakelock
sStatsd.informPollAlarmFired(); statsd.informPollAlarmFired();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e); Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
}
} }
} }
} }
@@ -351,17 +355,16 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "Time to trigger periodic alarm."); Log.d(TAG, "Time to trigger periodic alarm.");
} }
synchronized (sStatsdLock) { IStatsd statsd = getStatsdNonblocking();
if (sStatsd == null) { if (statsd == null) {
Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing."); Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
return; return;
} }
try { try {
// Two-way call to statsd to retain AlarmManager wakelock // Two-way call to statsd to retain AlarmManager wakelock
sStatsd.informAlarmForSubscriberTriggeringFired(); statsd.informAlarmForSubscriberTriggeringFired();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e); Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
}
} }
// AlarmManager releases its own wakelock here. // AlarmManager releases its own wakelock here.
} }
@@ -379,17 +382,19 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
return; return;
} }
Log.i(TAG, "StatsCompanionService noticed a shutdown."); if (DEBUG) {
synchronized (sStatsdLock) { Log.i(TAG, "StatsCompanionService noticed a shutdown.");
if (sStatsd == null) { }
Log.w(TAG, "Could not access statsd to inform it of a shutdown event."); IStatsd statsd = getStatsdNonblocking();
return; if (statsd == null) {
} Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
try { return;
sStatsd.informDeviceShutdown(); }
} catch (Exception e) { try {
Log.w(TAG, "Failed to inform statsd of a shutdown event.", e); // two way binder call
} statsd.informDeviceShutdown();
} catch (Exception e) {
Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
} }
} }
} }
@@ -515,7 +520,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
} }
} }
@Override @Override // Binder call
public void triggerUidSnapshot() { public void triggerUidSnapshot() {
StatsCompanion.enforceStatsdCallingUid(); StatsCompanion.enforceStatsdCallingUid();
synchronized (sStatsdLock) { synchronized (sStatsdLock) {
@@ -525,7 +530,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Failed to trigger uid snapshot.", e); Log.e(TAG, "Failed to trigger uid snapshot.", e);
} finally { } finally {
restoreCallingIdentity(token); Binder.restoreCallingIdentity(token);
} }
} }
} }
@@ -539,15 +544,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// Statsd related code // Statsd related code
/** /**
* Fetches the statsd IBinder service. * Fetches the statsd IBinder service. This is a blocking call.
* Note: This should only be called from sayHiToStatsd. All other clients should use the cached * Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
* sStatsd with a null check. * the cached sStatsd via {@link #getStatsdNonblocking()}.
*/ */
private static IStatsd fetchStatsdService() { private IStatsd fetchStatsdService(StatsdDeathRecipient deathRecipient) {
return IStatsd.Stub.asInterface(StatsFrameworkInitializer synchronized (sStatsdLock) {
.getStatsServiceManager() if (sStatsd == null) {
.getStatsdServiceRegisterer() sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
.get()); .getStatsServiceManager()
.getStatsdServiceRegisterer()
.get());
if (sStatsd != null) {
try {
sStatsd.asBinder().linkToDeath(deathRecipient, /* flags */ 0);
} catch (RemoteException e) {
Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed");
statsdNotReadyLocked();
}
}
}
return sStatsd;
}
} }
/** /**
@@ -567,67 +585,84 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
* statsd. * statsd.
*/ */
private void sayHiToStatsd() { private void sayHiToStatsd() {
synchronized (sStatsdLock) { if (getStatsdNonblocking() != null) {
if (sStatsd != null) { Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
Log.e(TAG, "Trying to fetch statsd, but it was already fetched", new IllegalStateException(
new IllegalStateException( "sStatsd is not null when being fetched"));
"sStatsd is not null when being fetched")); return;
return; }
} StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient();
sStatsd = fetchStatsdService(); IStatsd statsd = fetchStatsdService(deathRecipient);
if (sStatsd == null) { if (statsd == null) {
Log.i(TAG, Log.i(TAG,
"Could not yet find statsd to tell it that StatsCompanion is " "Could not yet find statsd to tell it that StatsCompanion is "
+ "alive."); + "alive.");
return; return;
} }
mStatsManagerService.statsdReady(sStatsd); mStatsManagerService.statsdReady(statsd);
if (DEBUG) Log.d(TAG, "Saying hi to statsd"); if (DEBUG) Log.d(TAG, "Saying hi to statsd");
try {
statsd.statsCompanionReady();
cancelAnomalyAlarm();
cancelPullingAlarm();
BroadcastReceiver appUpdateReceiver = new AppUpdateReceiver();
BroadcastReceiver userUpdateReceiver = new UserUpdateReceiver();
BroadcastReceiver shutdownEventReceiver = new ShutdownEventReceiver();
// Setup broadcast receiver for updates.
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);
// Setup receiver for user initialize (which happens once for a new user)
// and
// if a user is removed.
filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
filter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
// Setup receiver for device reboots or shutdowns.
filter = new IntentFilter(Intent.ACTION_REBOOT);
filter.addAction(Intent.ACTION_SHUTDOWN);
mContext.registerReceiverForAllUsers(
shutdownEventReceiver, filter, null, null);
// Only add the receivers if the registration is successful.
deathRecipient.addRegisteredBroadcastReceivers(
List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver));
final long token = Binder.clearCallingIdentity();
try { try {
sStatsd.statsCompanionReady(); // Pull the latest state of UID->app name, version mapping when
// If the statsCompanionReady two-way binder call returns, link to statsd. // statsd starts.
try { informAllUidsLocked(mContext);
sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0); } finally {
} catch (RemoteException e) { Binder.restoreCallingIdentity(token);
Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
forgetEverythingLocked();
}
// Setup broadcast receiver for updates.
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiverForAllUsers(mAppUpdateReceiver, filter, null, null);
// Setup receiver for user initialize (which happens once for a new user)
// and
// if a user is removed.
filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
filter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverForAllUsers(mUserUpdateReceiver, filter, null, null);
// Setup receiver for device reboots or shutdowns.
filter = new IntentFilter(Intent.ACTION_REBOOT);
filter.addAction(Intent.ACTION_SHUTDOWN);
mContext.registerReceiverForAllUsers(
mShutdownEventReceiver, filter, null, null);
final long token = Binder.clearCallingIdentity();
try {
// Pull the latest state of UID->app name, version mapping when
// statsd starts.
informAllUidsLocked(mContext);
} finally {
restoreCallingIdentity(token);
}
Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
} catch (RemoteException e) {
Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
forgetEverythingLocked();
} }
Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
} catch (RemoteException e) {
Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
} }
} }
private class StatsdDeathRecipient implements IBinder.DeathRecipient { private class StatsdDeathRecipient implements IBinder.DeathRecipient {
private List<BroadcastReceiver> mReceiversToUnregister;
StatsdDeathRecipient() {
mReceiversToUnregister = new ArrayList<>();
}
public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) {
synchronized (sStatsdLock) {
mReceiversToUnregister.addAll(receivers);
}
}
@Override @Override
public void binderDied() { public void binderDied() {
Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers"); Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
@@ -656,20 +691,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
} }
} }
} }
forgetEverythingLocked(); // We only unregister in binder death becaseu receivers can only be unregistered
// once, or an IllegalArgumentException is thrown.
for (BroadcastReceiver receiver: mReceiversToUnregister) {
mContext.unregisterReceiver(receiver);
}
statsdNotReadyLocked();
} }
} }
} }
@GuardedBy("StatsCompanionService.sStatsdLock") private void statsdNotReadyLocked() {
private void forgetEverythingLocked() {
sStatsd = null; sStatsd = null;
mContext.unregisterReceiver(mAppUpdateReceiver);
mContext.unregisterReceiver(mUserUpdateReceiver);
mContext.unregisterReceiver(mShutdownEventReceiver);
cancelAnomalyAlarm();
cancelPullingAlarm();
mStatsManagerService.statsdNotReady(); mStatsManagerService.statsdNotReady();
} }