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:
Rajeev Kumar
2021-03-04 04:32:52 +00:00
committed by Android (Google) Code Review
11 changed files with 205 additions and 13 deletions

View File

@@ -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()));

View File

@@ -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;

View File

@@ -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

View File

@@ -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() {

View File

@@ -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(

View File

@@ -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(

View File

@@ -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(

View File

@@ -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,

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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;
}