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