1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "ActivityManagerNativeTest"
18 
19 #include <android-base/logging.h>
20 #include <android/activity_manager.h>
21 #include <binder/PermissionController.h>
22 #include <binder/ProcessState.h>
23 #include <gtest/gtest.h>
24 
25 constexpr const char* kTestPackage = "com.android.tests.UidImportanceHelper";
26 constexpr const char* kTestActivity = "com.android.tests.UidImportanceHelper.MainActivity";
27 constexpr int64_t kEventTimeoutUs = 500000;
28 
29 //-----------------------------------------------------------------
30 class ActivityManagerNativeTest : public ::testing::Test {
31 protected:
ActivityManagerNativeTest()32     ActivityManagerNativeTest() : mUidObserver(nullptr), mTestAppUid(-1), mLastUidImportance(-1) {}
33 
~ActivityManagerNativeTest()34     virtual ~ActivityManagerNativeTest() {}
35 
36     /* Test setup*/
SetUp()37     virtual void SetUp() { android::ProcessState::self()->startThreadPool(); }
38 
39     /* Test tear down */
TearDown()40     virtual void TearDown() {}
41 
waitForImportance(int32_t val,int64_t timeoutUs)42     bool waitForImportance(int32_t val, int64_t timeoutUs) {
43         std::unique_lock lock(mLock);
44 
45         if (mLastUidImportance != val && timeoutUs > 0) {
46             mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
47         }
48 
49         return mLastUidImportance == val;
50     }
51 
onUidImportanceChanged(uid_t uid,int32_t uidImportance)52     void onUidImportanceChanged(uid_t uid, int32_t uidImportance) {
53         LOG(ERROR) << "OnUidImportance: uid " << uid << ", importance " << uidImportance;
54         std::unique_lock lock(mLock);
55 
56         if (uid == mTestAppUid) {
57             mLastUidImportance = uidImportance;
58             mCondition.notify_one();
59         }
60     }
61 
OnUidImportance(uid_t uid,int32_t uidImportance,void * cookie)62     static void OnUidImportance(uid_t uid, int32_t uidImportance, void* cookie) {
63         ActivityManagerNativeTest* owner = reinterpret_cast<ActivityManagerNativeTest*>(cookie);
64         owner->onUidImportanceChanged(uid, uidImportance);
65     }
66 
67     AActivityManager_UidImportanceListener* mUidObserver;
68     uid_t mTestAppUid;
69     std::mutex mLock;
70     std::condition_variable mCondition;
71     int32_t mLastUidImportance;
72 };
73 
getUidForPackage(const char * packageName,uid_t & uid)74 static bool getUidForPackage(const char* packageName, /*inout*/ uid_t& uid) {
75     android::PermissionController pc;
76     uid = pc.getPackageUid(android::String16(packageName), 0);
77     if (uid <= 0) {
78         ALOGE("Unknown package: '%s'", packageName);
79         return false;
80     }
81     return true;
82 }
83 
84 struct ShellHelper {
RunCmdShellHelper85     static bool RunCmd(const std::string& cmdStr) {
86         int ret = system(cmdStr.c_str());
87         if (ret != 0) {
88             LOG(ERROR) << "Failed to run cmd: " << cmdStr << ", exitcode " << ret;
89             return false;
90         }
91         return true;
92     }
93 
StartShellHelper94     static bool Start(const char* packageName, const char* activityName) {
95         return RunCmd("am start -W " + std::string(packageName) + "/" + std::string(activityName) +
96                       " &> /dev/null");
97     }
98 
StopShellHelper99     static bool Stop(const char* packageName) {
100         return RunCmd("am force-stop " + std::string(packageName));
101     }
102 };
103 
104 //-------------------------------------------------------------------------------------------------
TEST_F(ActivityManagerNativeTest,testUidImportance)105 TEST_F(ActivityManagerNativeTest, testUidImportance) {
106     pid_t selfPid = ::getpid();
107     uid_t selfUid = ::getuid();
108 
109     uid_t testAppUid;
110     EXPECT_TRUE(getUidForPackage(kTestPackage, testAppUid));
111     LOG(INFO) << "testUidImportance: uidselfUid" << selfUid << ", selfPid " << selfPid
112               << ", testAppUid " << testAppUid;
113     mTestAppUid = testAppUid;
114 
115     // Expect the initial UidImportance to be GONE.
116     EXPECT_FALSE(AActivityManager_isUidActive(testAppUid));
117     EXPECT_EQ(AActivityManager_getUidImportance(testAppUid), AACTIVITYMANAGER_IMPORTANCE_GONE);
118 
119     mUidObserver = AActivityManager_addUidImportanceListener(&OnUidImportance,
120                                                              AACTIVITYMANAGER_IMPORTANCE_FOREGROUND,
121                                                              (void*)this);
122     EXPECT_TRUE(mUidObserver != nullptr);
123 
124     // Start the test activity, and expect to receive UidImportance change to FOREGROUND.
125     EXPECT_TRUE(ShellHelper::Start(kTestPackage, kTestActivity));
126     EXPECT_TRUE(waitForImportance(AACTIVITYMANAGER_IMPORTANCE_FOREGROUND, kEventTimeoutUs));
127     EXPECT_TRUE(AActivityManager_isUidActive(testAppUid));
128     EXPECT_EQ(AActivityManager_getUidImportance(testAppUid),
129               AACTIVITYMANAGER_IMPORTANCE_FOREGROUND);
130 
131     // Stop the test activity, and expect to receive UidImportance change to GONE.
132     EXPECT_TRUE(ShellHelper::Stop(kTestPackage));
133     EXPECT_TRUE(waitForImportance(AACTIVITYMANAGER_IMPORTANCE_GONE, kEventTimeoutUs));
134     EXPECT_FALSE(AActivityManager_isUidActive(testAppUid));
135     EXPECT_EQ(AActivityManager_getUidImportance(testAppUid), AACTIVITYMANAGER_IMPORTANCE_GONE);
136 
137     AActivityManager_removeUidImportanceListener(mUidObserver);
138     mUidObserver = nullptr;
139 }
140