• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 "CachedAppOptimizer"
18 //#define LOG_NDEBUG 0
19 
20 #include <dirent.h>
21 #include <stddef.h>
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include <android-base/stringprintf.h>
28 #include <android-base/file.h>
29 
30 #include <nativehelper/JNIHelp.h>
31 #include <android_runtime/AndroidRuntime.h>
32 #include <binder/IPCThreadState.h>
33 #include <jni.h>
34 #include <processgroup/processgroup.h>
35 
36 using android::base::StringPrintf;
37 using android::base::WriteStringToFile;
38 
39 #define SYNC_RECEIVED_WHILE_FROZEN (1)
40 #define ASYNC_RECEIVED_WHILE_FROZEN (2)
41 
42 namespace android {
43 
44 // This performs per-process reclaim on all processes belonging to non-app UIDs.
45 // For the most part, these are non-zygote processes like Treble HALs, but it
46 // also includes zygote-derived processes that run in system UIDs, like bluetooth
47 // or potentially some mainline modules. The only process that should definitely
48 // not be compacted is system_server, since compacting system_server around the
49 // time of BOOT_COMPLETE could result in perceptible issues.
com_android_server_am_CachedAppOptimizer_compactSystem(JNIEnv *,jobject)50 static void com_android_server_am_CachedAppOptimizer_compactSystem(JNIEnv *, jobject) {
51     std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
52     struct dirent* current;
53     while ((current = readdir(proc.get()))) {
54         if (current->d_type != DT_DIR) {
55             continue;
56         }
57 
58         // don't compact system_server, rely on persistent compaction during screen off
59         // in order to avoid mmap_sem-related stalls
60         if (atoi(current->d_name) == getpid()) {
61             continue;
62         }
63 
64         std::string status_name = StringPrintf("/proc/%s/status", current->d_name);
65         struct stat status_info;
66 
67         if (stat(status_name.c_str(), &status_info) != 0) {
68             // must be some other directory that isn't a pid
69             continue;
70         }
71 
72         // android.os.Process.FIRST_APPLICATION_UID
73         if (status_info.st_uid >= 10000) {
74             continue;
75         }
76 
77         std::string reclaim_path = StringPrintf("/proc/%s/reclaim", current->d_name);
78         WriteStringToFile(std::string("all"), reclaim_path);
79     }
80 }
81 
com_android_server_am_CachedAppOptimizer_enableFreezerInternal(JNIEnv * env,jobject clazz,jboolean enable)82 static void com_android_server_am_CachedAppOptimizer_enableFreezerInternal(
83         JNIEnv *env, jobject clazz, jboolean enable) {
84     bool success = true;
85 
86     if (enable) {
87         success = SetTaskProfiles(0, {"FreezerEnabled"}, true);
88     } else {
89         success = SetTaskProfiles(0, {"FreezerDisabled"}, true);
90     }
91 
92     if (!success) {
93         jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
94     }
95 }
96 
com_android_server_am_CachedAppOptimizer_freezeBinder(JNIEnv * env,jobject clazz,jint pid,jboolean freeze)97 static void com_android_server_am_CachedAppOptimizer_freezeBinder(
98         JNIEnv *env, jobject clazz, jint pid, jboolean freeze) {
99 
100     if (IPCThreadState::freeze(pid, freeze, 100 /* timeout [ms] */) != 0) {
101         jniThrowException(env, "java/lang/RuntimeException", "Unable to freeze/unfreeze binder");
102     }
103 }
104 
com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo(JNIEnv * env,jobject clazz,jint pid)105 static jint com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo(JNIEnv *env,
106         jobject clazz, jint pid) {
107     bool syncReceived = false, asyncReceived = false;
108 
109     int error = IPCThreadState::getProcessFreezeInfo(pid, &syncReceived, &asyncReceived);
110 
111     if (error < 0) {
112         jniThrowException(env, "java/lang/RuntimeException", strerror(error));
113     }
114 
115     jint retVal = 0;
116 
117     if(syncReceived) {
118         retVal |= SYNC_RECEIVED_WHILE_FROZEN;;
119     }
120 
121     if(asyncReceived) {
122         retVal |= ASYNC_RECEIVED_WHILE_FROZEN;
123     }
124 
125     return retVal;
126 }
127 
128 static const JNINativeMethod sMethods[] = {
129     /* name, signature, funcPtr */
130     {"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
131     {"enableFreezerInternal", "(Z)V",
132         (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
133     {"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder},
134     {"getBinderFreezeInfo", "(I)I",
135         (void*)com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo}
136 };
137 
register_android_server_am_CachedAppOptimizer(JNIEnv * env)138 int register_android_server_am_CachedAppOptimizer(JNIEnv* env)
139 {
140     return jniRegisterNativeMethods(env, "com/android/server/am/CachedAppOptimizer",
141                                     sMethods, NELEM(sMethods));
142 }
143 
144 }
145