diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index fcab8c10db9eb..c58b91e39d0f2 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1555,6 +1555,7 @@ public class AppOpsManager { private final long[] mRejectTimes; private final int mDuration; private final int mProxyUid; + private final boolean mRunning; private final String mProxyPackageName; public OpEntry(int op, int mode, long time, long rejectTime, int duration, @@ -1566,12 +1567,13 @@ public class AppOpsManager { mTimes[0] = time; mRejectTimes[0] = rejectTime; mDuration = duration; + mRunning = duration == -1; mProxyUid = proxyUid; mProxyPackageName = proxyPackage; } public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration, - int proxyUid, String proxyPackage) { + boolean running, int proxyUid, String proxyPackage) { mOp = op; mMode = mode; mTimes = new long[_NUM_UID_STATE]; @@ -1579,10 +1581,16 @@ public class AppOpsManager { System.arraycopy(times, 0, mTimes, 0, _NUM_UID_STATE); System.arraycopy(rejectTimes, 0, mRejectTimes, 0, _NUM_UID_STATE); mDuration = duration; + mRunning = running; mProxyUid = proxyUid; mProxyPackageName = proxyPackage; } + public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration, + int proxyUid, String proxyPackage) { + this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage); + } + public int getOp() { return mOp; } @@ -1632,7 +1640,7 @@ public class AppOpsManager { } public boolean isRunning() { - return mDuration == -1; + return mRunning; } public int getDuration() { @@ -1659,6 +1667,7 @@ public class AppOpsManager { dest.writeLongArray(mTimes); dest.writeLongArray(mRejectTimes); dest.writeInt(mDuration); + dest.writeBoolean(mRunning); dest.writeInt(mProxyUid); dest.writeString(mProxyPackageName); } @@ -1669,6 +1678,7 @@ public class AppOpsManager { mTimes = source.createLongArray(); mRejectTimes = source.createLongArray(); mDuration = source.readInt(); + mRunning = source.readBoolean(); mProxyUid = source.readInt(); mProxyPackageName = source.readString(); } diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 3beebcba6c5d7..aa86ea8b03e2f 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -812,11 +812,12 @@ public class AppOpsService extends IAppOpsService.Stub { resOps = new ArrayList<>(); for (int j=0; j(); } - long duration = curOp.duration == -1 + final boolean running = curOp.duration == -1; + final long duration = running ? (elapsedNow - curOp.startRealtime) : curOp.duration; resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, - curOp.rejectTime, (int) duration, curOp.proxyUid, + curOp.rejectTime, (int) duration, running, curOp.proxyUid, curOp.proxyPackageName)); } } diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java index ea0fe455672b5..7f397d6a2cfc8 100644 --- a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java @@ -18,6 +18,8 @@ package com.android.server.appops; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -36,6 +38,8 @@ import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.List; + /** * Tests app ops version upgrades */ @@ -107,6 +111,46 @@ public class AppOpsActiveWatcherTest { verifyNoMoreInteractions(listener); } + @Test + public void testIsRunning() throws Exception { + final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); + // Start the op + appOpsManager.startOp(AppOpsManager.OP_CAMERA); + + assertTrue("Camera should be running", isCameraOn(appOpsManager)); + + // Finish the op + appOpsManager.finishOp(AppOpsManager.OP_CAMERA); + + assertFalse("Camera should not be running", isCameraOn(appOpsManager)); + } + + private boolean isCameraOn(AppOpsManager appOpsManager) { + List packages + = appOpsManager.getPackagesForOps(new int[] {AppOpsManager.OP_CAMERA}); + // AppOpsManager can return null when there is no requested data. + if (packages != null) { + final int numPackages = packages.size(); + for (int packageInd = 0; packageInd < numPackages; packageInd++) { + AppOpsManager.PackageOps packageOp = packages.get(packageInd); + List opEntries = packageOp.getOps(); + if (opEntries != null) { + final int numOps = opEntries.size(); + for (int opInd = 0; opInd < numOps; opInd++) { + AppOpsManager.OpEntry opEntry = opEntries.get(opInd); + if (opEntry.getOp() == AppOpsManager.OP_CAMERA) { + if (opEntry.isRunning()) { + return true; + } + } + } + } + } + } + + return false; + } + private static Context getContext() { return InstrumentationRegistry.getContext(); }