• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 "Freezer"
18 //#define LOG_NDEBUG 0
19 #define ATRACE_TAG ATRACE_TAG_ACTIVITY_MANAGER
20 
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 
25 #include <android-base/logging.h>
26 #include <android-base/unique_fd.h>
27 #include <binder/IPCThreadState.h>
28 #include <nativehelper/JNIHelp.h>
29 #include <processgroup/processgroup.h>
30 
31 namespace android {
32 namespace {
33 
34 // Binder status bit flags.
35 static const int SYNC_RECEIVED_WHILE_FROZEN = 1;
36 static const int ASYNC_RECEIVED_WHILE_FROZEN = 2;
37 static const int TXNS_PENDING_WHILE_FROZEN = 4;
38 
freezeBinder(JNIEnv * env,jobject,jint pid,jboolean freeze,jint timeout_ms)39 jint freezeBinder(JNIEnv* env, jobject, jint pid, jboolean freeze, jint timeout_ms) {
40     jint retVal = IPCThreadState::freeze(pid, freeze, timeout_ms);
41     if (retVal != 0 && retVal != -EAGAIN) {
42         jniThrowException(env, "java/lang/RuntimeException", "Unable to freeze/unfreeze binder");
43     }
44 
45     return retVal;
46 }
47 
getBinderFreezeInfo(JNIEnv * env,jobject,jint pid)48 jint getBinderFreezeInfo(JNIEnv *env, jobject, jint pid) {
49     uint32_t syncReceived = 0, asyncReceived = 0;
50 
51     int error = IPCThreadState::getProcessFreezeInfo(pid, &syncReceived, &asyncReceived);
52 
53     if (error < 0) {
54         jniThrowException(env, "java/lang/RuntimeException", strerror(error));
55     }
56 
57     jint retVal = 0;
58 
59     // bit 0 of sync_recv goes to bit 0 of retVal
60     retVal |= syncReceived & SYNC_RECEIVED_WHILE_FROZEN;
61     // bit 0 of async_recv goes to bit 1 of retVal
62     retVal |= (asyncReceived << 1) & ASYNC_RECEIVED_WHILE_FROZEN;
63     // bit 1 of sync_recv goes to bit 2 of retVal
64     retVal |= (syncReceived << 1) & TXNS_PENDING_WHILE_FROZEN;
65 
66     return retVal;
67 }
68 
isFreezerSupported(JNIEnv * env,jclass)69 bool isFreezerSupported(JNIEnv *env, jclass) {
70     std::string path;
71     if (!CgroupGetAttributePathForTask("FreezerState", getpid(), &path)) {
72         ALOGI("No attribute for FreezerState");
73         return false;
74     }
75     base::unique_fd fid(open(path.c_str(), O_RDONLY));
76     if (fid < 0) {
77         ALOGI("Cannot open freezer path \"%s\": %s", path.c_str(), strerror(errno));
78         return false;
79     }
80 
81     char state;
82     if (::read(fid, &state, 1) != 1) {
83         ALOGI("Failed to read freezer state: %s", strerror(errno));
84         return false;
85     }
86     if (state != '1' && state != '0') {
87         ALOGE("Unexpected value in cgroup.freeze: %d", state);
88         return false;
89     }
90 
91     uid_t uid = getuid();
92     pid_t pid = getpid();
93 
94     uint32_t syncReceived = 0, asyncReceived = 0;
95     int error = IPCThreadState::getProcessFreezeInfo(pid, &syncReceived, &asyncReceived);
96     if (error < 0) {
97         ALOGE("Unable to read freezer info: %s", strerror(errno));
98         return false;
99     }
100 
101     if (!isProfileValidForProcess("Frozen", uid, pid)
102             || !isProfileValidForProcess("Unfrozen", uid, pid)) {
103         ALOGE("Missing freezer profiles");
104         return false;
105     }
106 
107     return true;
108 }
109 
110 static const JNINativeMethod sMethods[] = {
nativeIsFreezerSupported()111     {"nativeIsFreezerSupported",    "()Z",       (void*) isFreezerSupported },
nativeFreezeBinder(IZI)112     {"nativeFreezeBinder",          "(IZI)I",    (void*) freezeBinder },
nativeGetBinderFreezeInfo(I)113     {"nativeGetBinderFreezeInfo",   "(I)I",      (void*) getBinderFreezeInfo },
114 };
115 
116 } // end of anonymous namespace
117 
register_android_server_am_Freezer(JNIEnv * env)118 int register_android_server_am_Freezer(JNIEnv* env)
119 {
120     char const *className = "com/android/server/am/Freezer";
121     return jniRegisterNativeMethods(env, className, sMethods, NELEM(sMethods));
122 }
123 
124 } // end of namespace android
125