Merge changes I0bd9becd,I1f2967dc into sc-dev
* changes: Add new component usage event (2/2) Add new component usage event (1/2)
This commit is contained in:
@@ -273,10 +273,12 @@ public final class JobServiceContext implements ServiceConnection {
|
||||
// another binding flag for that.
|
||||
bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
|
||||
| Context.BIND_ALMOST_PERCEPTIBLE
|
||||
| Context.BIND_ALLOW_NETWORK_ACCESS;
|
||||
| Context.BIND_ALLOW_NETWORK_ACCESS
|
||||
| Context.BIND_NOT_APP_COMPONENT_USAGE;
|
||||
} else {
|
||||
bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
|
||||
| Context.BIND_NOT_PERCEPTIBLE;
|
||||
| Context.BIND_NOT_PERCEPTIBLE
|
||||
| Context.BIND_NOT_APP_COMPONENT_USAGE;
|
||||
}
|
||||
binding = mContext.bindServiceAsUser(intent, this, bindFlags,
|
||||
UserHandle.of(job.getUserId()));
|
||||
|
||||
@@ -333,11 +333,20 @@ public final class UsageEvents implements Parcelable {
|
||||
*/
|
||||
public static final int LOCUS_ID_SET = 30;
|
||||
|
||||
/**
|
||||
* An event type denoting that a component in the package has been used (e.g. broadcast
|
||||
* receiver, service, content provider). This generally matches up with usage that would
|
||||
* cause an app to leave force stop. The component itself is not provided as we are only
|
||||
* interested in whether the package is used, not the component itself.
|
||||
* @hide
|
||||
*/
|
||||
public static final int APP_COMPONENT_USED = 31;
|
||||
|
||||
/**
|
||||
* Keep in sync with the greatest event type value.
|
||||
* @hide
|
||||
*/
|
||||
public static final int MAX_EVENT_TYPE = 30;
|
||||
public static final int MAX_EVENT_TYPE = 31;
|
||||
|
||||
/** @hide */
|
||||
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
|
||||
|
||||
@@ -369,6 +369,15 @@ public abstract class Context {
|
||||
/*********** Public flags above this line ***********/
|
||||
/*********** Hidden flags below this line ***********/
|
||||
|
||||
/**
|
||||
* Flag for {@link #bindService}: This flag is only intended to be used by the system to
|
||||
* indicate that a service binding is not considered as real package component usage and should
|
||||
* not generate a {@link android.app.usage.UsageEvents.Event#APP_COMPONENT_USED} event in usage
|
||||
* stats.
|
||||
* @hide
|
||||
*/
|
||||
public static final int BIND_NOT_APP_COMPONENT_USAGE = 0x00008000;
|
||||
|
||||
/**
|
||||
* Flag for {@link #bindService}: allow the process hosting the target service to be treated
|
||||
* as if it's as important as a perceptible app to the user and avoid the oom killer killing
|
||||
|
||||
@@ -78,15 +78,15 @@ public class UsageStatsPersistenceTest {
|
||||
"VALID_FLAG_BITS", "UNASSIGNED_TOKEN", "MAX_EVENT_TYPE"};
|
||||
// All fields in this list are final constants defining event types and not persisted
|
||||
private static final String[] EVENT_TYPES = {"NONE", "ACTIVITY_DESTROYED", "ACTIVITY_PAUSED",
|
||||
"ACTIVITY_RESUMED", "ACTIVITY_STOPPED", "CHOOSER_ACTION", "CONFIGURATION_CHANGE",
|
||||
"CONTINUE_PREVIOUS_DAY", "CONTINUING_FOREGROUND_SERVICE", "DEVICE_SHUTDOWN",
|
||||
"DEVICE_STARTUP", "END_OF_DAY", "FLUSH_TO_DISK", "FOREGROUND_SERVICE_START",
|
||||
"FOREGROUND_SERVICE_STOP", "KEYGUARD_HIDDEN", "KEYGUARD_SHOWN", "LOCUS_ID_SET",
|
||||
"MOVE_TO_BACKGROUND", "MOVE_TO_FOREGROUND", "NOTIFICATION_INTERRUPTION",
|
||||
"NOTIFICATION_SEEN", "ROLLOVER_FOREGROUND_SERVICE", "SCREEN_INTERACTIVE",
|
||||
"SCREEN_NON_INTERACTIVE", "SHORTCUT_INVOCATION", "SLICE_PINNED", "SLICE_PINNED_PRIV",
|
||||
"STANDBY_BUCKET_CHANGED", "SYSTEM_INTERACTION", "USER_INTERACTION", "USER_STOPPED",
|
||||
"USER_UNLOCKED"};
|
||||
"ACTIVITY_RESUMED", "ACTIVITY_STOPPED", "APP_COMPONENT_USED", "CHOOSER_ACTION",
|
||||
"CONFIGURATION_CHANGE", "CONTINUE_PREVIOUS_DAY", "CONTINUING_FOREGROUND_SERVICE",
|
||||
"DEVICE_SHUTDOWN", "DEVICE_STARTUP", "END_OF_DAY", "FLUSH_TO_DISK",
|
||||
"FOREGROUND_SERVICE_START", "FOREGROUND_SERVICE_STOP", "KEYGUARD_HIDDEN",
|
||||
"KEYGUARD_SHOWN", "LOCUS_ID_SET", "MOVE_TO_BACKGROUND", "MOVE_TO_FOREGROUND",
|
||||
"NOTIFICATION_INTERRUPTION", "NOTIFICATION_SEEN", "ROLLOVER_FOREGROUND_SERVICE",
|
||||
"SCREEN_INTERACTIVE", "SCREEN_NON_INTERACTIVE", "SHORTCUT_INVOCATION", "SLICE_PINNED",
|
||||
"SLICE_PINNED_PRIV", "STANDBY_BUCKET_CHANGED", "SYSTEM_INTERACTION", "USER_INTERACTION",
|
||||
"USER_STOPPED", "USER_UNLOCKED"};
|
||||
|
||||
@Test
|
||||
public void testUsageEventsFields() {
|
||||
|
||||
@@ -86,6 +86,7 @@ import android.app.Service;
|
||||
import android.app.ServiceStartArgs;
|
||||
import android.app.admin.DevicePolicyEventLogger;
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.appwidget.AppWidgetManagerInternal;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledSince;
|
||||
@@ -2464,6 +2465,10 @@ public final class ActiveServices {
|
||||
s.setAllowedBgFgsStartsByBinding(true);
|
||||
}
|
||||
|
||||
if ((flags & Context.BIND_NOT_APP_COMPONENT_USAGE) != 0) {
|
||||
s.isNotAppComponentUsage = true;
|
||||
}
|
||||
|
||||
if (s.app != null) {
|
||||
updateServiceClientActivitiesLocked(s.app.mServices, c, true);
|
||||
}
|
||||
@@ -3332,6 +3337,14 @@ public final class ActiveServices {
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Report usage if binding is from a different package except for explicitly exempted
|
||||
// bindings
|
||||
if (!r.appInfo.packageName.equals(r.mRecentCallingPackage)
|
||||
&& !r.isNotAppComponentUsage) {
|
||||
mAm.mUsageStatsService.reportEvent(
|
||||
r.packageName, r.userId, UsageEvents.Event.APP_COMPONENT_USED);
|
||||
}
|
||||
|
||||
// Service is now being launched, its package can't be stopped.
|
||||
try {
|
||||
AppGlobals.getPackageManager().setPackageStoppedState(
|
||||
|
||||
@@ -2684,6 +2684,11 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
if (mUsageStatsService != null) {
|
||||
mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode(), taskRoot);
|
||||
if (event == Event.ACTIVITY_RESUMED) {
|
||||
// Report component usage as an activity is an app component
|
||||
mUsageStatsService.reportEvent(
|
||||
activity.getPackageName(), userId, Event.APP_COMPONENT_USED);
|
||||
}
|
||||
}
|
||||
ContentCaptureManagerInternal contentCaptureService = mContentCaptureService;
|
||||
if (contentCaptureService != null && (event == Event.ACTIVITY_PAUSED
|
||||
@@ -6099,6 +6104,10 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
|
||||
}
|
||||
|
||||
// Report usage as process is persistent and being started.
|
||||
mUsageStatsService.reportEvent(info.packageName, UserHandle.getUserId(app.uid),
|
||||
Event.APP_COMPONENT_USED);
|
||||
|
||||
// This package really, really can not be stopped.
|
||||
try {
|
||||
AppGlobals.getPackageManager().setPackageStoppedState(
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.app.AppOpsManager;
|
||||
import android.app.BroadcastOptions;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.usage.UsageEvents.Event;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.IIntentReceiver;
|
||||
@@ -52,6 +53,7 @@ import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.permission.IPermissionManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.EventLog;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseIntArray;
|
||||
@@ -1634,6 +1636,13 @@ public final class BroadcastQueue {
|
||||
brOptions.getTemporaryAppAllowlistReason());
|
||||
}
|
||||
|
||||
// Report that a component is used for explicit broadcasts.
|
||||
if (!r.intent.isExcludingStopped() && r.curComponent != null
|
||||
&& !TextUtils.equals(r.curComponent.getPackageName(), r.callerPackage)) {
|
||||
mService.mUsageStatsService.reportEvent(
|
||||
r.curComponent.getPackageName(), r.userId, Event.APP_COMPONENT_USED);
|
||||
}
|
||||
|
||||
// Broadcast is being executed, its package can't be stopped.
|
||||
try {
|
||||
AppGlobals.getPackageManager().setPackageStoppedState(
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.app.AppOpsManager;
|
||||
import android.app.ApplicationExitInfo;
|
||||
import android.app.ContentProviderHolder;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.usage.UsageEvents.Event;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
@@ -57,6 +58,7 @@ import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
@@ -412,6 +414,12 @@ public class ContentProviderHelper {
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
|
||||
try {
|
||||
if (!TextUtils.equals(cpr.appInfo.packageName, callingPackage)) {
|
||||
// Report component used since a content provider is being bound.
|
||||
mService.mUsageStatsService.reportEvent(
|
||||
cpr.appInfo.packageName, userId, Event.APP_COMPONENT_USED);
|
||||
}
|
||||
|
||||
// Content provider is now in use, its package can't be stopped.
|
||||
try {
|
||||
checkTime(startTime,
|
||||
|
||||
@@ -107,6 +107,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
|
||||
boolean delayed; // are we waiting to start this service in the background?
|
||||
boolean fgRequired; // is the service required to go foreground after starting?
|
||||
boolean fgWaiting; // is a timeout for going foreground already scheduled?
|
||||
boolean isNotAppComponentUsage; // is service binding not considered component/package usage?
|
||||
boolean isForeground; // is service currently in foreground mode?
|
||||
int foregroundId; // Notification ID of last foreground req.
|
||||
Notification foregroundNoti; // Notification record of foreground state.
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.usage;
|
||||
|
||||
import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
|
||||
import static android.app.usage.UsageEvents.Event.APP_COMPONENT_USED;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mockitoSession;
|
||||
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.app.usage.UsageEvents.Event;
|
||||
import android.content.Context;
|
||||
import android.os.SystemClock;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.usage.UserUsageStatsService.StatsUpdatedListener;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class UserUsageStatsServiceTest {
|
||||
private static final int TEST_USER_ID = 0;
|
||||
private static final String TEST_PACKAGE_NAME = "test.package";
|
||||
private static final long TIME_INTERVAL_MILLIS = DateUtils.DAY_IN_MILLIS;
|
||||
|
||||
private UserUsageStatsService mService;
|
||||
private MockitoSession mMockitoSession;
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private StatsUpdatedListener mStatsUpdatedListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mMockitoSession = mockitoSession()
|
||||
.initMocks(this)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
|
||||
File dir = new File(InstrumentationRegistry.getContext().getCacheDir(), "test");
|
||||
mService = new UserUsageStatsService(mContext, TEST_USER_ID, dir, mStatsUpdatedListener);
|
||||
|
||||
HashMap<String, Long> installedPkgs = new HashMap<>();
|
||||
installedPkgs.put(TEST_PACKAGE_NAME, System.currentTimeMillis());
|
||||
|
||||
mService.init(System.currentTimeMillis(), installedPkgs);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mMockitoSession != null) {
|
||||
mMockitoSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReportEvent_eventAppearsInQueries() {
|
||||
Event event = new Event(ACTIVITY_RESUMED, SystemClock.elapsedRealtime());
|
||||
event.mPackage = TEST_PACKAGE_NAME;
|
||||
mService.reportEvent(event);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long startTime = now - TIME_INTERVAL_MILLIS;
|
||||
UsageEvents events = mService.queryEventsForPackage(
|
||||
startTime, now, TEST_PACKAGE_NAME, false /* includeTaskRoot */);
|
||||
|
||||
boolean hasTestEvent = false;
|
||||
while (events != null && events.hasNextEvent()) {
|
||||
Event outEvent = new Event();
|
||||
events.getNextEvent(outEvent);
|
||||
if (outEvent.mEventType == ACTIVITY_RESUMED) {
|
||||
hasTestEvent = true;
|
||||
}
|
||||
}
|
||||
assertTrue(hasTestEvent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReportEvent_packageUsedEventNotTracked() {
|
||||
Event event = new Event(APP_COMPONENT_USED, SystemClock.elapsedRealtime());
|
||||
event.mPackage = TEST_PACKAGE_NAME;
|
||||
mService.reportEvent(event);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long startTime = now - TIME_INTERVAL_MILLIS;
|
||||
UsageEvents events = mService.queryEventsForPackage(
|
||||
startTime, now, TEST_PACKAGE_NAME, false /* includeTaskRoot */);
|
||||
|
||||
boolean hasTestEvent = false;
|
||||
while (events != null && events.hasNextEvent()) {
|
||||
Event outEvent = new Event();
|
||||
events.getNextEvent(outEvent);
|
||||
if (outEvent.mEventType == APP_COMPONENT_USED) {
|
||||
hasTestEvent = true;
|
||||
}
|
||||
}
|
||||
assertFalse(hasTestEvent);
|
||||
}
|
||||
}
|
||||
@@ -303,7 +303,9 @@ class UserUsageStatsService {
|
||||
// FLUSH_TO_DISK is a private event.
|
||||
&& event.mEventType != Event.FLUSH_TO_DISK
|
||||
// DEVICE_SHUTDOWN is added to event list after reboot.
|
||||
&& event.mEventType != Event.DEVICE_SHUTDOWN) {
|
||||
&& event.mEventType != Event.DEVICE_SHUTDOWN
|
||||
// We aren't interested in every instance of the APP_COMPONENT_USED event.
|
||||
&& event.mEventType != Event.APP_COMPONENT_USED) {
|
||||
currentDailyStats.addEvent(event);
|
||||
}
|
||||
|
||||
@@ -1176,6 +1178,8 @@ class UserUsageStatsService {
|
||||
return "USER_STOPPED";
|
||||
case Event.LOCUS_ID_SET:
|
||||
return "LOCUS_ID_SET";
|
||||
case Event.APP_COMPONENT_USED:
|
||||
return "APP_COMPONENT_USED";
|
||||
default:
|
||||
return "UNKNOWN_TYPE_" + eventType;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user