Merge "Add api to check if an app is in foreground or not."
This commit is contained in:
committed by
Android (Google) Code Review
commit
2294db42d3
@@ -46,6 +46,14 @@ package com.android.server.am {
|
||||
|
||||
}
|
||||
|
||||
package com.android.server.appop {
|
||||
|
||||
public interface AppOpsManagerLocal {
|
||||
method public boolean isUidInForeground(int);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package com.android.server.pm {
|
||||
|
||||
public interface PackageManagerLocal {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.appop;
|
||||
|
||||
import android.annotation.SystemApi;
|
||||
|
||||
/**
|
||||
* In-process app ops API for mainline modules.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
|
||||
public interface AppOpsManagerLocal {
|
||||
|
||||
/**
|
||||
* Determines if the UID is in foreground in the same way as how foreground runtime
|
||||
* permissions work.
|
||||
*
|
||||
* @return Returns {@code true} if the given UID is in the foreground.
|
||||
*/
|
||||
boolean isUidInForeground(int uid);
|
||||
}
|
||||
@@ -978,6 +978,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
public void publish() {
|
||||
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
|
||||
LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
|
||||
LocalServices.addService(AppOpsManagerLocal.class, new AppOpsManagerLocalImpl());
|
||||
}
|
||||
|
||||
/** Handler for work when packages are removed or updated */
|
||||
@@ -6138,6 +6139,15 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
|
||||
}
|
||||
}
|
||||
|
||||
private final class AppOpsManagerLocalImpl implements AppOpsManagerLocal {
|
||||
@Override
|
||||
public boolean isUidInForeground(int uid) {
|
||||
synchronized (AppOpsService.this) {
|
||||
return mUidStateTracker.isUidInForeground(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
|
||||
@Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
|
||||
synchronized (AppOpsService.this) {
|
||||
|
||||
@@ -88,6 +88,11 @@ interface AppOpsUidStateTracker {
|
||||
*/
|
||||
int getUidState(int uid);
|
||||
|
||||
/**
|
||||
* Determines if the uid is in foreground.
|
||||
*/
|
||||
boolean isUidInForeground(int uid);
|
||||
|
||||
/**
|
||||
* Given a uid, code, and mode, resolve any foregroundness to MODE_IGNORED or MODE_ALLOWED
|
||||
*/
|
||||
|
||||
@@ -24,8 +24,10 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
|
||||
import static android.app.ActivityManager.ProcessCapability;
|
||||
import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
|
||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||
import static android.app.AppOpsManager.MODE_FOREGROUND;
|
||||
import static android.app.AppOpsManager.MODE_IGNORED;
|
||||
import static android.app.AppOpsManager.OP_CAMERA;
|
||||
import static android.app.AppOpsManager.OP_NONE;
|
||||
import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
|
||||
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
|
||||
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
|
||||
@@ -124,60 +126,32 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
|
||||
@Override
|
||||
public int evalMode(int uid, int code, int mode) {
|
||||
if (mode != AppOpsManager.MODE_FOREGROUND) {
|
||||
if (mode != MODE_FOREGROUND) {
|
||||
return mode;
|
||||
}
|
||||
|
||||
int uidStateValue;
|
||||
int capability;
|
||||
boolean visibleAppWidget;
|
||||
boolean pendingTop;
|
||||
boolean tempAllowlist;
|
||||
uidStateValue = getUidState(uid);
|
||||
capability = getUidCapability(uid);
|
||||
visibleAppWidget = getUidVisibleAppWidget(uid);
|
||||
pendingTop = mActivityManagerInternal.isPendingTopUid(uid);
|
||||
tempAllowlist = mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid);
|
||||
int uidState = getUidState(uid);
|
||||
int uidCapability = getUidCapability(uid);
|
||||
int result = evalModeInternal(uid, code, uidState, uidCapability);
|
||||
|
||||
int result = evalMode(uidStateValue, code, mode, capability, visibleAppWidget, pendingTop,
|
||||
tempAllowlist);
|
||||
mEventLog.logEvalForegroundMode(uid, uidStateValue, capability, code, result);
|
||||
mEventLog.logEvalForegroundMode(uid, uidState, uidCapability, code, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int evalMode(int uidState, int code, int mode, int capability,
|
||||
boolean appWidgetVisible, boolean pendingTop, boolean tempAllowlist) {
|
||||
if (mode != AppOpsManager.MODE_FOREGROUND) {
|
||||
return mode;
|
||||
}
|
||||
private int evalModeInternal(int uid, int code, int uidState, int uidCapability) {
|
||||
|
||||
if (appWidgetVisible || pendingTop || tempAllowlist) {
|
||||
if (getUidVisibleAppWidget(uid) || mActivityManagerInternal.isPendingTopUid(uid)
|
||||
|| mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid)) {
|
||||
return MODE_ALLOWED;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case AppOpsManager.OP_FINE_LOCATION:
|
||||
case AppOpsManager.OP_COARSE_LOCATION:
|
||||
case AppOpsManager.OP_MONITOR_LOCATION:
|
||||
case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
|
||||
if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) == 0) {
|
||||
return MODE_IGNORED;
|
||||
} else {
|
||||
return MODE_ALLOWED;
|
||||
}
|
||||
case OP_CAMERA:
|
||||
if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) == 0) {
|
||||
return MODE_IGNORED;
|
||||
} else {
|
||||
return MODE_ALLOWED;
|
||||
}
|
||||
case OP_RECORD_AUDIO:
|
||||
case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
|
||||
if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) == 0) {
|
||||
return MODE_IGNORED;
|
||||
} else {
|
||||
return MODE_ALLOWED;
|
||||
}
|
||||
int opCapability = getOpCapability(code);
|
||||
if (opCapability != PROCESS_CAPABILITY_NONE) {
|
||||
if ((uidCapability & opCapability) == 0) {
|
||||
return MODE_IGNORED;
|
||||
} else {
|
||||
return MODE_ALLOWED;
|
||||
}
|
||||
}
|
||||
|
||||
if (uidState > AppOpsManager.resolveFirstUnrestrictedUidState(code)) {
|
||||
@@ -187,6 +161,28 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
|
||||
return MODE_ALLOWED;
|
||||
}
|
||||
|
||||
private int getOpCapability(int opCode) {
|
||||
switch (opCode) {
|
||||
case AppOpsManager.OP_FINE_LOCATION:
|
||||
case AppOpsManager.OP_COARSE_LOCATION:
|
||||
case AppOpsManager.OP_MONITOR_LOCATION:
|
||||
case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
|
||||
return PROCESS_CAPABILITY_FOREGROUND_LOCATION;
|
||||
case OP_CAMERA:
|
||||
return PROCESS_CAPABILITY_FOREGROUND_CAMERA;
|
||||
case OP_RECORD_AUDIO:
|
||||
case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
|
||||
return PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
|
||||
default:
|
||||
return PROCESS_CAPABILITY_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUidInForeground(int uid) {
|
||||
return evalMode(uid, OP_NONE, MODE_FOREGROUND) == MODE_ALLOWED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUidStateChangedCallback(Executor executor, UidStateChangedCallback callback) {
|
||||
if (mUidStateChangedCallbacks.containsKey(callback)) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* TODO(b/146466118) remove this javadoc tag
|
||||
*/
|
||||
@android.annotation.Hide
|
||||
package com.android.server.appop;
|
||||
@@ -35,6 +35,8 @@ import static android.app.AppOpsManager.UID_STATE_TOP;
|
||||
import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -754,6 +756,32 @@ public class AppOpsUidStateTrackerTest {
|
||||
verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsUidInForegroundForBackgroundState() {
|
||||
procStateBuilder(UID)
|
||||
.backgroundState()
|
||||
.update();
|
||||
assertFalse(mIntf.isUidInForeground(UID));
|
||||
|
||||
procStateBuilder(UID)
|
||||
.nonExistentState()
|
||||
.update();
|
||||
assertFalse(mIntf.isUidInForeground(UID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsUidInForegroundForForegroundState() {
|
||||
procStateBuilder(UID)
|
||||
.topState()
|
||||
.update();
|
||||
assertTrue(mIntf.isUidInForeground(UID));
|
||||
|
||||
procStateBuilder(UID)
|
||||
.foregroundServiceState()
|
||||
.update();
|
||||
assertTrue(mIntf.isUidInForeground(UID));
|
||||
}
|
||||
|
||||
public void testUidStateChangedCallback(int initialState, int finalState) {
|
||||
int initialUidState = processStateToUidState(initialState);
|
||||
int finalUidState = processStateToUidState(finalState);
|
||||
@@ -806,7 +834,7 @@ public class AppOpsUidStateTrackerTest {
|
||||
private AppOpsUidStateTracker mIntf;
|
||||
private int mUid;
|
||||
private int mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
|
||||
private int mCapability = 0;
|
||||
private int mCapability = ActivityManager.PROCESS_CAPABILITY_NONE;
|
||||
|
||||
private UidProcStateUpdateBuilder(AppOpsUidStateTracker intf, int uid) {
|
||||
mUid = uid;
|
||||
|
||||
Reference in New Issue
Block a user