diff options
author | Chong Zhang <chz@google.com> | 2020-12-04 17:15:45 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-12-04 17:15:45 +0000 |
commit | cb95b8375bcdf7ce3ef02177f2dd3bc1bff9a195 (patch) | |
tree | 356b6012081e1896f60a076087af0954644958eb /native | |
parent | 686d72cea4bb1313ba9e2669a2587776b74e7d1e (diff) | |
parent | 8af87925eaf9ed2bc791ba9add34da8d137fcb9f (diff) |
Merge "Add ActivityManager UidImportanceListener to libandroid"
Diffstat (limited to 'native')
-rw-r--r-- | native/android/Android.bp | 5 | ||||
-rw-r--r-- | native/android/activity_manager.cpp | 226 | ||||
-rw-r--r-- | native/android/include_platform/android/activity_manager.h | 176 | ||||
-rw-r--r-- | native/android/libandroid.map.txt | 4 |
4 files changed, 411 insertions, 0 deletions
diff --git a/native/android/Android.bp b/native/android/Android.bp index 7793d6c45d5e..6db4da95f6db 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -36,6 +36,7 @@ cc_library_shared { defaults: ["libandroid_defaults"], srcs: [ + "activity_manager.cpp", "asset_manager.cpp", "choreographer.cpp", "configuration.cpp", @@ -95,6 +96,10 @@ cc_library_shared { include_dirs: ["bionic/libc/dns/include"], + local_include_dirs: [ "include_platform", ], + + export_include_dirs: [ "include_platform", ], + version_script: "libandroid.map.txt", stubs: { symbol_file: "libandroid.map.txt", diff --git a/native/android/activity_manager.cpp b/native/android/activity_manager.cpp new file mode 100644 index 000000000000..82f4569b871e --- /dev/null +++ b/native/android/activity_manager.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2020 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. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "AActivityManager" +#include <utils/Log.h> + +#include <android/activity_manager.h> +#include <binder/ActivityManager.h> + +namespace android { +namespace activitymanager { + +// Global instance of ActivityManager, service is obtained only on first use. +static ActivityManager gAm; +// String tag used with ActivityManager. +static const String16& getTag() { + static String16 tag("libandroid"); + return tag; +} + +struct UidObserver : public BnUidObserver, public virtual IBinder::DeathRecipient { + explicit UidObserver(const AActivityManager_onUidImportance& cb, + int32_t cutpoint, void* cookie) + : mCallback(cb), mImportanceCutpoint(cutpoint), mCookie(cookie), mRegistered(false) {} + bool registerSelf(); + void unregisterSelf(); + + // IUidObserver + void onUidGone(uid_t uid, bool disabled) override; + void onUidActive(uid_t uid) override; + void onUidIdle(uid_t uid, bool disabled) override; + void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq, + int32_t capability) override; + + // IBinder::DeathRecipient implementation + void binderDied(const wp<IBinder>& who) override; + + static int32_t procStateToImportance(int32_t procState); + static int32_t importanceToProcState(int32_t importance); + + AActivityManager_onUidImportance mCallback; + int32_t mImportanceCutpoint; + void* mCookie; + std::mutex mRegisteredLock; + bool mRegistered GUARDED_BY(mRegisteredLock); +}; + +//static +int32_t UidObserver::procStateToImportance(int32_t procState) { + // TODO: remove this after adding Importance to onUidStateChanged callback. + if (procState == ActivityManager::PROCESS_STATE_NONEXISTENT) { + return AACTIVITYMANAGER_IMPORTANCE_GONE; + } else if (procState >= ActivityManager::PROCESS_STATE_HOME) { + return AACTIVITYMANAGER_IMPORTANCE_CACHED; + } else if (procState == ActivityManager::PROCESS_STATE_HEAVY_WEIGHT) { + return AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE; + } else if (procState >= ActivityManager::PROCESS_STATE_TOP_SLEEPING) { + return AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING; + } else if (procState >= ActivityManager::PROCESS_STATE_SERVICE) { + return AACTIVITYMANAGER_IMPORTANCE_SERVICE; + } else if (procState >= ActivityManager::PROCESS_STATE_TRANSIENT_BACKGROUND) { + return AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE; + } else if (procState >= ActivityManager::PROCESS_STATE_IMPORTANT_FOREGROUND) { + return AACTIVITYMANAGER_IMPORTANCE_VISIBLE; + } else if (procState >= ActivityManager::PROCESS_STATE_FOREGROUND_SERVICE) { + return AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE; + } else { + return AACTIVITYMANAGER_IMPORTANCE_FOREGROUND; + } +} + +//static +int32_t UidObserver::importanceToProcState(int32_t importance) { + // TODO: remove this after adding Importance to onUidStateChanged callback. + if (importance == AACTIVITYMANAGER_IMPORTANCE_GONE) { + return ActivityManager::PROCESS_STATE_NONEXISTENT; + } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_CACHED) { + return ActivityManager::PROCESS_STATE_HOME; + } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE) { + return ActivityManager::PROCESS_STATE_HEAVY_WEIGHT; + } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING) { + return ActivityManager::PROCESS_STATE_TOP_SLEEPING; + } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_SERVICE) { + return ActivityManager::PROCESS_STATE_SERVICE; + } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE) { + return ActivityManager::PROCESS_STATE_TRANSIENT_BACKGROUND; + } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_VISIBLE) { + return ActivityManager::PROCESS_STATE_IMPORTANT_FOREGROUND; + } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE) { + return ActivityManager::PROCESS_STATE_FOREGROUND_SERVICE; + } else { + return ActivityManager::PROCESS_STATE_TOP; + } +} + + +void UidObserver::onUidGone(uid_t uid, bool disabled __unused) { + std::scoped_lock lock{mRegisteredLock}; + + if (mRegistered && mCallback) { + mCallback(uid, AACTIVITYMANAGER_IMPORTANCE_GONE, mCookie); + } +} + +void UidObserver::onUidActive(uid_t uid __unused) {} + +void UidObserver::onUidIdle(uid_t uid __unused, bool disabled __unused) {} + +void UidObserver::onUidStateChanged(uid_t uid, int32_t procState, + int64_t procStateSeq __unused, + int32_t capability __unused) { + std::scoped_lock lock{mRegisteredLock}; + + if (mRegistered && mCallback) { + mCallback(uid, procStateToImportance(procState), mCookie); + } +} + +void UidObserver::binderDied(const wp<IBinder>& /*who*/) { + // ActivityManager is dead, try to re-register. + { + std::scoped_lock lock{mRegisteredLock}; + // If client already unregistered, don't try to re-register. + if (!mRegistered) { + return; + } + // Clear mRegistered to re-register. + mRegistered = false; + } + registerSelf(); +} + +bool UidObserver::registerSelf() { + std::scoped_lock lock{mRegisteredLock}; + if (mRegistered) { + return true; + } + + status_t res = gAm.linkToDeath(this); + if (res != OK) { + ALOGE("UidObserver: Failed to linkToDeath with ActivityManager (err %d)", res); + return false; + } + + // TODO: it seems only way to get all changes is to set cutoff to PROCESS_STATE_UNKNOWN. + // But there is no equivalent of PROCESS_STATE_UNKNOWN in the UidImportance. + // If mImportanceCutpoint is < 0, use PROCESS_STATE_UNKNOWN instead. + res = gAm.registerUidObserver( + this, + ActivityManager::UID_OBSERVER_GONE | ActivityManager::UID_OBSERVER_PROCSTATE, + (mImportanceCutpoint < 0) ? ActivityManager::PROCESS_STATE_UNKNOWN + : importanceToProcState(mImportanceCutpoint), + getTag()); + if (res != OK) { + ALOGE("UidObserver: Failed to register with ActivityManager (err %d)", res); + gAm.unlinkToDeath(this); + return false; + } + + mRegistered = true; + ALOGV("UidObserver: Registered with ActivityManager"); + return true; +} + +void UidObserver::unregisterSelf() { + std::scoped_lock lock{mRegisteredLock}; + + if (mRegistered) { + gAm.unregisterUidObserver(this); + gAm.unlinkToDeath(this); + mRegistered = false; + } + + ALOGV("UidObserver: Unregistered with ActivityManager"); +} + +} // activitymanager +} // android + +using namespace android; +using namespace activitymanager; + +struct AActivityManager_UidImportanceListener : public UidObserver { +}; + +AActivityManager_UidImportanceListener* AActivityManager_addUidImportanceListener( + AActivityManager_onUidImportance onUidImportance, int32_t importanceCutpoint, void* cookie) { + sp<UidObserver> observer(new UidObserver(onUidImportance, importanceCutpoint, cookie)); + if (observer == nullptr || !observer->registerSelf()) { + return nullptr; + } + observer->incStrong((void *)AActivityManager_addUidImportanceListener); + return static_cast<AActivityManager_UidImportanceListener*>(observer.get()); +} + +void AActivityManager_removeUidImportanceListener( + AActivityManager_UidImportanceListener* listener) { + if (listener != nullptr) { + UidObserver* observer = static_cast<UidObserver*>(listener); + observer->unregisterSelf(); + observer->decStrong((void *)AActivityManager_addUidImportanceListener); + } +} + +bool AActivityManager_isUidActive(uid_t uid) { + return gAm.isUidActive(uid, getTag()); +} + +int32_t AActivityManager_getUidImportance(uid_t uid) { + return UidObserver::procStateToImportance(gAm.getUidProcessState(uid, getTag())); +} + diff --git a/native/android/include_platform/android/activity_manager.h b/native/android/include_platform/android/activity_manager.h new file mode 100644 index 000000000000..0ecd56d512a2 --- /dev/null +++ b/native/android/include_platform/android/activity_manager.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2020 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. + */ + +#ifndef __AACTIVITYMANAGER_H__ +#define __AACTIVITYMANAGER_H__ + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +struct AActivityManager_UidImportanceListener; +typedef struct AActivityManager_UidImportanceListener AActivityManager_UidImportanceListener; + +/** + * Callback interface when Uid Importance has changed for a uid. + * + * This callback will be called on an arbitrary thread. Calls to a given listener will be + * serialized. + * + * @param uid the uid for which the importance has changed. + * @param uidImportance the new uidImportance for the uid. + * @cookie the same cookie when the UidImportanceListener was added. + * + * Introduced in API 31. + */ +typedef void (*AActivityManager_onUidImportance)(uid_t uid, int32_t uidImportance, void* cookie); + +/** + * ActivityManager Uid Importance constants. + * + * Introduced in API 31. + */ +enum { + /** + * Constant for Uid Importance: This process is running the + * foreground UI; that is, it is the thing currently at the top of the screen + * that the user is interacting with. + */ + AACTIVITYMANAGER_IMPORTANCE_FOREGROUND = 100, + + /** + * Constant for Uid Importance: This process is running a foreground + * service, for example to perform music playback even while the user is + * not immediately in the app. This generally indicates that the process + * is doing something the user actively cares about. + */ + AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE = 125, + + /** + * Constant for Uid Importance: This process is running something + * that is actively visible to the user, though not in the immediate + * foreground. This may be running a window that is behind the current + * foreground (so paused and with its state saved, not interacting with + * the user, but visible to them to some degree); it may also be running + * other services under the system's control that it inconsiders important. + */ + AACTIVITYMANAGER_IMPORTANCE_VISIBLE = 200, + + /** + * Constant for Uid Importance: This process is not something the user + * is directly aware of, but is otherwise perceptible to them to some degree. + */ + AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE = 230, + + /** + * Constant for Uid Importance: This process contains services + * that should remain running. These are background services apps have + * started, not something the user is aware of, so they may be killed by + * the system relatively freely (though it is generally desired that they + * stay running as long as they want to). + */ + AACTIVITYMANAGER_IMPORTANCE_SERVICE = 300, + + /** + * Constant for Uid Importance: This process is running the foreground + * UI, but the device is asleep so it is not visible to the user. Though the + * system will try hard to keep its process from being killed, in all other + * ways we consider it a kind of cached process, with the limitations that go + * along with that state: network access, running background services, etc. + */ + AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING = 325, + + /** + * Constant for Uid Importance: This process is running an + * application that can not save its state, and thus can't be killed + * while in the background. This will be used with apps that have + * {@link android.R.attr#cantSaveState} set on their application tag. + */ + AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE = 350, + + /** + * Constant for Uid Importance: This process process contains + * cached code that is expendable, not actively running any app components + * we care about. + */ + AACTIVITYMANAGER_IMPORTANCE_CACHED = 400, + + /** + * Constant for Uid Importance: This process does not exist. + */ + AACTIVITYMANAGER_IMPORTANCE_GONE = 1000, +}; + +#if __ANDROID_API__ >= 31 + +/** + * Adds a UidImportanceListener to the ActivityManager. + * + * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission. + * + * @param onUidImportance the listener callback that will receive change reports. + * + * @param importanceCutpoint the level of importance in which the caller is interested + * in differences. For example, if AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE is used + * here, you will receive a call each time a uid's importance transitions between being + * <= AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE and > AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE. + * + * @param cookie a cookie that will be passed back to the listener callback. + * + * @return an opaque pointer of AActivityManager_UidImportanceListener, or nullptr + * upon failure. Upon success, the returned AActivityManager_UidImportanceListener pointer + * must be removed and released through AActivityManager_removeUidImportanceListener. + */ +AActivityManager_UidImportanceListener* AActivityManager_addUidImportanceListener( + AActivityManager_onUidImportance onUidImportance, + int32_t importanceCutpoint, + void* cookie) __INTRODUCED_IN(31); + +/** + * Removes a UidImportanceListener that was added with AActivityManager_addUidImportanceListener. + * + * When this returns, it's guaranteed the listener callback will no longer be invoked. + * + * @param listener the UidImportanceListener to be removed. + */ +void AActivityManager_removeUidImportanceListener( + AActivityManager_UidImportanceListener* listener) __INTRODUCED_IN(31); + +/** + * Queries if a uid is currently active. + * + * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission. + * + * @return true if the uid is active, false otherwise. + */ +bool AActivityManager_isUidActive(uid_t uid) __INTRODUCED_IN(31); + +/** + * Queries the current Uid Importance value of a uid. + * + * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission. + * + * @param uid the uid for which the importance value is queried. + * @return the current uid importance value for uid. + */ +int32_t AActivityManager_getUidImportance(uid_t uid) __INTRODUCED_IN(31); + +#endif // __ANDROID_API__ >= 31 + +__END_DECLS + +#endif // __AACTIVITYMANAGER_H__ diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index eca67bd7d211..8fa3acf502bc 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -1,5 +1,9 @@ LIBANDROID { global: + AActivityManager_addUidImportanceListener; # apex # introduced=31 + AActivityManager_removeUidImportanceListener; # apex # introduced=31 + AActivityManager_isUidActive; # apex # introduced=31 + AActivityManager_getUidImportance; # apex # introduced=31 AAssetDir_close; AAssetDir_getNextFileName; AAssetDir_rewind; |