| /* |
| * Copyright (C) 2019 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.MAX_EVENT_TYPE; |
| |
| import static junit.framework.Assert.assertEquals; |
| import static junit.framework.Assert.assertTrue; |
| |
| import android.app.usage.UsageEvents; |
| import android.content.res.Configuration; |
| import android.test.suitebuilder.annotation.SmallTest; |
| |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.util.Locale; |
| |
| @RunWith(AndroidJUnit4.class) |
| @SmallTest |
| public class IntervalStatsTests { |
| private static final int NUMBER_OF_PACKAGES = 7; |
| private static final int NUMBER_OF_EVENTS_PER_PACKAGE = 200; |
| private static final int NUMBER_OF_EVENTS = NUMBER_OF_PACKAGES * NUMBER_OF_EVENTS_PER_PACKAGE; |
| |
| private long mEndTime = 0; |
| |
| private void populateIntervalStats(IntervalStats intervalStats) { |
| final int timeProgression = 23; |
| long time = System.currentTimeMillis() - (NUMBER_OF_EVENTS * timeProgression); |
| |
| intervalStats.majorVersion = 7; |
| intervalStats.minorVersion = 8; |
| intervalStats.beginTime = time; |
| intervalStats.interactiveTracker.count = 2; |
| intervalStats.interactiveTracker.duration = 111111; |
| intervalStats.nonInteractiveTracker.count = 3; |
| intervalStats.nonInteractiveTracker.duration = 222222; |
| intervalStats.keyguardShownTracker.count = 4; |
| intervalStats.keyguardShownTracker.duration = 333333; |
| intervalStats.keyguardHiddenTracker.count = 5; |
| intervalStats.keyguardHiddenTracker.duration = 4444444; |
| |
| for (int i = 0; i < NUMBER_OF_EVENTS; i++) { |
| UsageEvents.Event event = new UsageEvents.Event(); |
| final int packageInt = ((i / 3) % NUMBER_OF_PACKAGES); // clusters of 3 events |
| event.mPackage = "fake.package.name" + packageInt; |
| if (packageInt == 3) { |
| // Third app is an instant app |
| event.mFlags |= UsageEvents.Event.FLAG_IS_PACKAGE_INSTANT_APP; |
| } |
| |
| final int instanceId = i % 11; |
| event.mClass = ".fake.class.name" + instanceId; |
| event.mTimeStamp = time; |
| event.mEventType = i % (MAX_EVENT_TYPE + 1); //"random" event type |
| event.mInstanceId = instanceId; |
| |
| |
| final int rootPackageInt = (i % 5); // 5 "apps" start each task |
| event.mTaskRootPackage = "fake.package.name" + rootPackageInt; |
| |
| final int rootClassInt = i % 6; |
| event.mTaskRootClass = ".fake.class.name" + rootClassInt; |
| |
| switch (event.mEventType) { |
| case UsageEvents.Event.CONFIGURATION_CHANGE: |
| event.mConfiguration = new Configuration(); //empty config |
| break; |
| case UsageEvents.Event.SHORTCUT_INVOCATION: |
| event.mShortcutId = "shortcut" + (i % 8); //"random" shortcut |
| break; |
| case UsageEvents.Event.STANDBY_BUCKET_CHANGED: |
| //"random" bucket and reason |
| event.mBucketAndReason = (((i % 5 + 1) * 10) << 16) & (i % 5 + 1) << 8; |
| break; |
| case UsageEvents.Event.NOTIFICATION_INTERRUPTION: |
| event.mNotificationChannelId = "channel" + (i % 5); //"random" channel |
| break; |
| case UsageEvents.Event.LOCUS_ID_SET: |
| event.mLocusId = "locus" + (i % 7); //"random" locus |
| break; |
| } |
| |
| intervalStats.addEvent(event); |
| intervalStats.update(event.mPackage, event.mClass, event.mTimeStamp, event.mEventType, |
| event.mInstanceId); |
| |
| time += timeProgression; // Arbitrary progression of time |
| } |
| mEndTime = time; |
| |
| final Configuration config1 = new Configuration(); |
| config1.fontScale = 3.3f; |
| config1.mcc = 4; |
| intervalStats.getOrCreateConfigurationStats(config1); |
| |
| final Configuration config2 = new Configuration(); |
| config2.mnc = 5; |
| config2.setLocale(new Locale("en", "US")); |
| intervalStats.getOrCreateConfigurationStats(config2); |
| |
| intervalStats.activeConfiguration = config2; |
| } |
| |
| @Test |
| public void testObfuscation() { |
| final IntervalStats intervalStats = new IntervalStats(); |
| populateIntervalStats(intervalStats); |
| |
| final PackagesTokenData packagesTokenData = new PackagesTokenData(); |
| intervalStats.obfuscateData(packagesTokenData); |
| |
| // data is populated with 7 different "apps" |
| assertEquals(packagesTokenData.tokensToPackagesMap.size(), NUMBER_OF_PACKAGES); |
| assertEquals(packagesTokenData.packagesToTokensMap.size(), NUMBER_OF_PACKAGES); |
| assertEquals(packagesTokenData.counter, NUMBER_OF_PACKAGES + 1); |
| |
| assertEquals(intervalStats.events.size(), NUMBER_OF_EVENTS); |
| assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES); |
| } |
| |
| @Test |
| public void testDeobfuscation() { |
| final IntervalStats intervalStats = new IntervalStats(); |
| populateIntervalStats(intervalStats); |
| |
| final PackagesTokenData packagesTokenData = new PackagesTokenData(); |
| intervalStats.obfuscateData(packagesTokenData); |
| intervalStats.deobfuscateData(packagesTokenData); |
| |
| // ensure deobfuscation doesn't update any of the mappings data |
| assertEquals(packagesTokenData.tokensToPackagesMap.size(), NUMBER_OF_PACKAGES); |
| assertEquals(packagesTokenData.packagesToTokensMap.size(), NUMBER_OF_PACKAGES); |
| assertEquals(packagesTokenData.counter, NUMBER_OF_PACKAGES + 1); |
| |
| // ensure deobfuscation didn't remove any events or usage stats |
| assertEquals(intervalStats.events.size(), NUMBER_OF_EVENTS); |
| assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES); |
| } |
| |
| @Test |
| public void testBadDataOnDeobfuscation() { |
| final IntervalStats intervalStats = new IntervalStats(); |
| populateIntervalStats(intervalStats); |
| |
| final PackagesTokenData packagesTokenData = new PackagesTokenData(); |
| intervalStats.obfuscateData(packagesTokenData); |
| intervalStats.packageStats.clear(); |
| |
| // remove the mapping for token 2 |
| packagesTokenData.tokensToPackagesMap.remove(2); |
| |
| intervalStats.deobfuscateData(packagesTokenData); |
| // deobfuscation should have removed all events mapped to package token 2 |
| assertEquals(intervalStats.events.size(), |
| NUMBER_OF_EVENTS - NUMBER_OF_EVENTS_PER_PACKAGE - 1); |
| assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES - 1); |
| } |
| |
| @Test |
| public void testBadPackageDataOnDeobfuscation() { |
| final IntervalStats intervalStats = new IntervalStats(); |
| populateIntervalStats(intervalStats); |
| |
| final PackagesTokenData packagesTokenData = new PackagesTokenData(); |
| intervalStats.obfuscateData(packagesTokenData); |
| intervalStats.packageStats.clear(); |
| |
| // remove mapping number 2 within package 3 (random) |
| packagesTokenData.tokensToPackagesMap.valueAt(3).remove(2); |
| |
| intervalStats.deobfuscateData(packagesTokenData); |
| // deobfuscation should not have removed all events for a package - however, it's possible |
| // that some events were removed because of how shortcut and notification events are handled |
| assertTrue(intervalStats.events.size() > NUMBER_OF_EVENTS - NUMBER_OF_EVENTS_PER_PACKAGE); |
| assertEquals(intervalStats.packageStats.size(), NUMBER_OF_PACKAGES); |
| } |
| } |