• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "com_android_internal_os_Zygote.h"
18 
19 #include <algorithm>
20 #include <android-base/logging.h>
21 #include <async_safe/log.h>
22 #include <cctype>
23 #include <chrono>
24 #include <core_jni_helpers.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <jni.h>
28 #include <nativehelper/JNIHelp.h>
29 #include <optional>
30 #include <poll.h>
31 #include <unistd.h>
32 #include <utility>
33 #include <utils/misc.h>
34 #include <sys/mman.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/system_properties.h>
38 #include <vector>
39 
40 namespace android {
41 
42 using namespace std::placeholders;
43 using android::base::StringPrintf;
44 using android::zygote::ZygoteFailure;
45 
46 // WARNING: Knows a little about the wire protocol used to communicate with Zygote.
47 
48 // Commands and nice names have large arbitrary size limits to avoid dynamic memory allocation.
49 constexpr size_t MAX_COMMAND_BYTES = 32768;
50 constexpr size_t NICE_NAME_BYTES = 128;
51 
52 // A buffer optionally bundled with a file descriptor from which we can fill it.
53 // Does not own the file descriptor; destroying a NativeCommandBuffer does not
54 // close the descriptor.
55 class NativeCommandBuffer {
56  public:
NativeCommandBuffer(int sourceFd)57   NativeCommandBuffer(int sourceFd): mEnd(0), mNext(0), mLinesLeft(0), mFd(sourceFd) {}
58 
59   // Read mNext line from mFd, filling mBuffer from file descriptor, as needed.
60   // Return a pair of pointers pointing to the first character, and one past the
61   // mEnd of the line, i.e. at the newline. Returns nothing on failure.
62   template<class FailFn>
readLine(FailFn fail_fn)63   std::optional<std::pair<char*, char*>> readLine(FailFn fail_fn) {
64     char* result = mBuffer + mNext;
65     while (true) {
66       // We have scanned up to, but not including mNext for this line's newline.
67       if (mNext == mEnd) {
68         if (mEnd == MAX_COMMAND_BYTES) {
69           return {};
70         }
71         if (mFd == -1) {
72           fail_fn("ZygoteCommandBuffer.readLine attempted to read from mFd -1");
73         }
74         ssize_t nread = TEMP_FAILURE_RETRY(read(mFd, mBuffer + mEnd, MAX_COMMAND_BYTES - mEnd));
75         if (nread <= 0) {
76           if (nread == 0) {
77             return {};
78           }
79           fail_fn(CREATE_ERROR("session socket read failed: %s", strerror(errno)));
80         } else if (nread == static_cast<ssize_t>(MAX_COMMAND_BYTES - mEnd)) {
81           // This is pessimistic by one character, but close enough.
82           fail_fn("ZygoteCommandBuffer overflowed: command too long");
83         }
84         mEnd += nread;
85       }
86       // UTF-8 does not allow newline to occur as part of a multibyte character.
87       char* nl = static_cast<char *>(memchr(mBuffer + mNext, '\n', mEnd - mNext));
88       if (nl == nullptr) {
89         mNext = mEnd;
90       } else {
91         mNext = nl - mBuffer + 1;
92         if (--mLinesLeft < 0) {
93           fail_fn("ZygoteCommandBuffer.readLine attempted to read past end of command");
94         }
95         return std::make_pair(result, nl);
96       }
97     }
98   }
99 
reset()100   void reset() {
101     mNext = 0;
102   }
103 
104   // Make sure the current command is fully buffered, without reading past the current command.
105   template<class FailFn>
readAllLines(FailFn fail_fn)106   void readAllLines(FailFn fail_fn) {
107      while (mLinesLeft > 0) {
108        readLine(fail_fn);
109     }
110   }
111 
clear()112   void clear() {
113     // Don't bother to actually clear the buffer; it'll be unmapped in the child anyway.
114     reset();
115     mNiceName[0] = '\0';
116     mEnd = 0;
117   }
118 
119   // Insert line into the mBuffer. Checks that the mBuffer is not associated with an mFd.
120   // Implicitly adds newline separators. Allows mBuffer contents to be explicitly set.
insert(const char * line,size_t lineLen)121   void insert(const char* line, size_t lineLen) {
122     DCHECK(mFd == -1);
123     CHECK(mEnd + lineLen < MAX_COMMAND_BYTES);
124     strncpy(mBuffer + mEnd, line, lineLen);
125     mBuffer[mEnd + lineLen] = '\n';
126     mEnd += lineLen + 1;
127   }
128 
129   // Start reading new command, return the number of arguments, leaving mBuffer positioned at the
130   // beginning of first argument. Return 0 on EOF.
131   template<class FailFn>
getCount(FailFn fail_fn)132   int getCount(FailFn fail_fn) {
133     mLinesLeft = 1;
134     auto line = readLine(fail_fn);
135     if (!line.has_value()) {
136       return 0;
137     }
138     char* countString = line.value().first;  // Newline terminated.
139     long nArgs = atol(countString);
140     if (nArgs <= 0 || nArgs >= static_cast<long>(MAX_COMMAND_BYTES / 2)) {
141       fail_fn(CREATE_ERROR("Unreasonable argument count %ld", nArgs));
142     }
143     mLinesLeft = nArgs;
144     return static_cast<int>(nArgs);
145   }
146 
147   // Is the mBuffer a simple fork command?
148   // We disallow request to wrap the child process, child zygotes, anything that
149   // mentions capabilities or requests uid < minUid.
150   // We insist that --setuid and --setgid arguments are explicitly included and that the
151   // command starts with --runtime-args.
152   // Assumes we are positioned at the beginning of the command after the argument count,
153   // and leaves the position at some indeterminate position in the buffer.
154   // As a side effect, this sets mNiceName to a non-empty string, if possible.
155   template<class FailFn>
isSimpleForkCommand(int minUid,FailFn fail_fn)156   bool isSimpleForkCommand(int minUid, FailFn fail_fn) {
157     if (mLinesLeft <= 0 || mLinesLeft >= static_cast<int32_t>(MAX_COMMAND_BYTES / 2)) {
158       return false;
159     }
160     static const char* RUNTIME_ARGS = "--runtime-args";
161     static const char* INVOKE_WITH = "--invoke-with";
162     static const char* CHILD_ZYGOTE = "--start-child-zygote";
163     static const char* SETUID = "--setuid=";
164     static const char* SETGID = "--setgid=";
165     static const char* CAPABILITIES = "--capabilities";
166     static const char* NICE_NAME = "--nice-name=";
167     static const size_t RA_LENGTH = strlen(RUNTIME_ARGS);
168     static const size_t IW_LENGTH = strlen(INVOKE_WITH);
169     static const size_t CZ_LENGTH = strlen(CHILD_ZYGOTE);
170     static const size_t SU_LENGTH = strlen(SETUID);
171     static const size_t SG_LENGTH = strlen(SETGID);
172     static const size_t CA_LENGTH = strlen(CAPABILITIES);
173     static const size_t NN_LENGTH = strlen(NICE_NAME);
174 
175     bool saw_setuid = false, saw_setgid = false;
176     bool saw_runtime_args = false;
177 
178     while (mLinesLeft > 0) {
179       auto read_result = readLine(fail_fn);
180       if (!read_result.has_value()) {
181         return false;
182       }
183       const auto [arg_start, arg_end] = read_result.value();
184       if (static_cast<size_t>(arg_end - arg_start) == RA_LENGTH &&
185           strncmp(arg_start, RUNTIME_ARGS, RA_LENGTH) == 0) {
186         saw_runtime_args = true;
187         continue;
188       }
189       if (static_cast<size_t>(arg_end - arg_start) >= NN_LENGTH &&
190           strncmp(arg_start, NICE_NAME, NN_LENGTH) == 0) {
191         size_t name_len = arg_end - (arg_start + NN_LENGTH);
192         size_t copy_len = std::min(name_len, NICE_NAME_BYTES - 1);
193         memcpy(mNiceName, arg_start + NN_LENGTH, copy_len);
194         mNiceName[copy_len] = '\0';
195         if (haveWrapProperty()) {
196           return false;
197         }
198         continue;
199       }
200       if (static_cast<size_t>(arg_end - arg_start) == IW_LENGTH &&
201           strncmp(arg_start, INVOKE_WITH, IW_LENGTH) == 0) {
202         // This also removes the need for invoke-with security checks here.
203         return false;
204       }
205       if (static_cast<size_t>(arg_end - arg_start) == CZ_LENGTH &&
206           strncmp(arg_start, CHILD_ZYGOTE, CZ_LENGTH) == 0) {
207         return false;
208       }
209       if (static_cast<size_t>(arg_end - arg_start) >= CA_LENGTH &&
210           strncmp(arg_start, CAPABILITIES, CA_LENGTH) == 0) {
211         return false;
212       }
213       if (static_cast<size_t>(arg_end - arg_start) >= SU_LENGTH &&
214           strncmp(arg_start, SETUID, SU_LENGTH) == 0) {
215         int uid = digitsVal(arg_start + SU_LENGTH, arg_end);
216         if (uid < minUid) {
217           return false;
218         }
219         saw_setuid = true;
220         continue;
221       }
222       if (static_cast<size_t>(arg_end - arg_start) >= SG_LENGTH &&
223           strncmp(arg_start, SETGID, SG_LENGTH) == 0) {
224         int gid = digitsVal(arg_start + SG_LENGTH, arg_end);
225         if (gid == -1) {
226           return false;
227         }
228         saw_setgid = true;
229       }
230       // ro.debuggable can be handled entirely in the child unless --invoke-with is also specified.
231       // Thus we do not need to check it here.
232     }
233     return saw_runtime_args && saw_setuid && saw_setgid;
234   }
235 
setFd(int new_fd)236   void setFd(int new_fd) {
237     mFd = new_fd;
238   }
239 
getFd() const240   int getFd() const {
241     return mFd;
242   }
243 
niceNameAddr() const244   const char* niceNameAddr() const {
245     return mNiceName;
246   }
247 
248   // Debug only:
logState() const249   void logState() const {
250     ALOGD("mbuffer starts with %c%c, nice name is %s, "
251           "mEnd = %u, mNext = %u, mLinesLeft = %d, mFd = %d",
252           mBuffer[0], (mBuffer[1] == '\n' ? ' ' : mBuffer[1]),
253           niceNameAddr(),
254           static_cast<unsigned>(mEnd), static_cast<unsigned>(mNext),
255           static_cast<int>(mLinesLeft), mFd);
256   }
257 
258  private:
haveWrapProperty()259   bool haveWrapProperty() {
260     static const char* WRAP = "wrap.";
261     static const size_t WRAP_LENGTH = strlen(WRAP);
262     char propNameBuf[WRAP_LENGTH + NICE_NAME_BYTES];
263     strcpy(propNameBuf, WRAP);
264     strlcpy(propNameBuf + WRAP_LENGTH, mNiceName, NICE_NAME_BYTES);
265     return __system_property_find(propNameBuf) != nullptr;
266   }
267   // Picky version of atoi(). No sign or unexpected characters allowed. Return -1 on failure.
digitsVal(char * start,char * end)268   static int digitsVal(char* start, char* end) {
269     int result = 0;
270     if (end - start > 6) {
271       return -1;
272     }
273     for (char* dp = start; dp < end; ++dp) {
274       if (*dp < '0' || *dp > '9') {
275         ALOGW("Argument failed integer format check");
276         return -1;
277       }
278       result = 10 * result + (*dp - '0');
279     }
280     return result;
281   }
282 
283   uint32_t mEnd;  // Index of first empty byte in the mBuffer.
284   uint32_t mNext;  // Index of first character past last line returned by readLine.
285   int32_t mLinesLeft;  // Lines in current command that haven't yet been read.
286   int mFd;  // Open file descriptor from which we can read more. -1 if none.
287   char mNiceName[NICE_NAME_BYTES];  // Always null terminated.
288   char mBuffer[MAX_COMMAND_BYTES];
289 };
290 
291 static int buffersAllocd(0);
292 
293 // Get a new NativeCommandBuffer. Can only be called once between freeNativeBuffer calls,
294 // so that only one buffer exists at a time.
com_android_internal_os_ZygoteCommandBuffer_getNativeBuffer(JNIEnv * env,jclass,jint fd)295 jlong com_android_internal_os_ZygoteCommandBuffer_getNativeBuffer(JNIEnv* env, jclass, jint fd) {
296   CHECK(buffersAllocd == 0);
297   ++buffersAllocd;
298   // MMap explicitly to get it page aligned.
299   void *bufferMem = mmap(NULL, sizeof(NativeCommandBuffer), PROT_READ | PROT_WRITE,
300                          MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
301   // Currently we mmap and unmap one for every request handled by the Java code.
302   // That could be improved, but unclear it matters.
303   if (bufferMem == MAP_FAILED) {
304     ZygoteFailure(env, nullptr, nullptr, "Failed to map argument buffer");
305   }
306   return (jlong) new(bufferMem) NativeCommandBuffer(fd);
307 }
308 
309 // Delete native command buffer.
com_android_internal_os_ZygoteCommandBuffer_freeNativeBuffer(JNIEnv * env,jclass,jlong j_buffer)310 void com_android_internal_os_ZygoteCommandBuffer_freeNativeBuffer(JNIEnv* env, jclass,
311                                                                   jlong j_buffer) {
312   CHECK(buffersAllocd == 1);
313   NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
314   n_buffer->~NativeCommandBuffer();
315   if (munmap(n_buffer, sizeof(NativeCommandBuffer)) != 0) {
316     ZygoteFailure(env, nullptr, nullptr, "Failed to unmap argument buffer");
317   }
318   --buffersAllocd;
319 }
320 
321 // Clear the buffer, read the line containing the count, and return the count.
com_android_internal_os_ZygoteCommandBuffer_nativeGetCount(JNIEnv * env,jclass,jlong j_buffer)322 jint com_android_internal_os_ZygoteCommandBuffer_nativeGetCount(JNIEnv* env, jclass,
323                                                                 jlong j_buffer) {
324   NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
325   auto fail_fn = std::bind(ZygoteFailure, env, nullptr, nullptr, _1);
326   return n_buffer->getCount(fail_fn);
327 }
328 
329 // Explicitly insert a string as the last line (argument) of the buffer.
com_android_internal_os_ZygoteCommandBuffer_insert(JNIEnv * env,jclass,jlong j_buffer,jstring line)330 void com_android_internal_os_ZygoteCommandBuffer_insert(JNIEnv* env, jclass, jlong j_buffer,
331                                                         jstring line) {
332   NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
333   size_t lineLen = static_cast<size_t>(env->GetStringUTFLength(line));
334   const char* cstring = env->GetStringUTFChars(line, NULL);
335   n_buffer->insert(cstring, lineLen);
336   env->ReleaseStringUTFChars(line, cstring);
337 }
338 
339 // Read a line from the buffer, refilling as necessary.
com_android_internal_os_ZygoteCommandBuffer_nativeNextArg(JNIEnv * env,jclass,jlong j_buffer)340 jstring com_android_internal_os_ZygoteCommandBuffer_nativeNextArg(JNIEnv* env, jclass,
341                                                                   jlong j_buffer) {
342   NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
343   auto fail_fn = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), nullptr, _1);
344   auto line = n_buffer->readLine(fail_fn);
345   if (!line.has_value()) {
346     fail_fn("Incomplete zygote command");
347   }
348   auto [cresult, endp] = line.value();
349   // OK to temporarily clobber the buffer, since this is not thread safe, and we're modifying
350   // the buffer anyway.
351   *endp = '\0';
352   jstring result = env->NewStringUTF(cresult);
353   *endp = '\n';
354   return result;
355 }
356 
getSocketPeerUid(int socket,const std::function<void (const std::string &)> & fail_fn)357 static uid_t getSocketPeerUid(int socket, const std::function<void(const std::string&)>& fail_fn) {
358   struct ucred credentials;
359   socklen_t cred_size = sizeof credentials;
360   if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1
361       || cred_size != sizeof credentials) {
362     fail_fn(CREATE_ERROR("Failed to get socket credentials, %s",
363                          strerror(errno)));
364   }
365 
366   return credentials.uid;
367 }
368 
369 // Read all lines from the current command into the buffer, and then reset the buffer, so
370 // we will start reading again at the beginning of the command, starting with the argument
371 // count. And we don't need access to the fd to do so.
com_android_internal_os_ZygoteCommandBuffer_nativeReadFullyAndReset(JNIEnv * env,jclass,jlong j_buffer)372 void com_android_internal_os_ZygoteCommandBuffer_nativeReadFullyAndReset(JNIEnv* env, jclass,
373                                                                          jlong j_buffer) {
374   NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
375   auto fail_fn = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), nullptr, _1);
376   n_buffer->readAllLines(fail_fn);
377   n_buffer->reset();
378 }
379 
380 // Fork a child as specified by the current command buffer, and refill the command
381 // buffer from the given socket. So long as the result is another simple fork command,
382 // repeat this process.
383 // It must contain a fork command, which is currently restricted not to fork another
384 // zygote or involve a wrapper process.
385 // The initial buffer should be partially or entirely read; we read it fully and reset it.
386 // When we return, the buffer contains the command we couldn't handle, and has been reset().
387 // We return false in the parent when we see a command we didn't understand, and thus the
388 // command in the buffer still needs to be executed.
389 // We return true in each child.
390 // We only process fork commands if the peer uid matches expected_uid.
391 // For every fork command after the first, we check that the requested uid is at
392 // least minUid.
393 NO_STACK_PROTECTOR
com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(JNIEnv * env,jclass,jlong j_buffer,jint zygote_socket_fd,jint expected_uid,jint minUid,jstring managed_nice_name)394 jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
395             JNIEnv* env,
396             jclass,
397             jlong j_buffer,
398             jint zygote_socket_fd,
399             jint expected_uid,
400             jint minUid,
401             jstring managed_nice_name) {
402 
403   ALOGI("Entering forkRepeatedly native zygote loop");
404   NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
405   int session_socket = n_buffer->getFd();
406   std::vector<int> session_socket_fds {session_socket};
407   auto fail_fn_1 = std::bind(ZygoteFailure, env, static_cast<const char*>(nullptr),
408                              static_cast<jstring>(managed_nice_name), _1);
409   // This binds to the nice name address; the actual names are updated by isSimpleForkCommand:
410   auto fail_fn_n = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(),
411                              static_cast<jstring>(nullptr), _1);
412   auto fail_fn_z = std::bind(ZygoteFailure, env, "zygote", nullptr, _1);
413 
414   struct pollfd fd_structs[2];
415   static const int ZYGOTE_IDX = 0;
416   static const int SESSION_IDX = 1;
417   fd_structs[ZYGOTE_IDX].fd = zygote_socket_fd;
418   fd_structs[ZYGOTE_IDX].events = POLLIN;
419   fd_structs[SESSION_IDX].fd = session_socket;
420   fd_structs[SESSION_IDX].events = POLLIN;
421 
422   struct timeval timeout;
423   socklen_t timeout_size = sizeof timeout;
424   if (getsockopt(session_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, &timeout_size) != 0) {
425     fail_fn_z("Failed to retrieve session socket timeout");
426   }
427 
428   uid_t peerUid = getSocketPeerUid(session_socket, fail_fn_1);
429   if (peerUid != static_cast<uid_t>(expected_uid)) {
430     return JNI_FALSE;
431   }
432   bool first_time = true;
433   do {
434     n_buffer->readAllLines(first_time ? fail_fn_1 : fail_fn_n);
435     n_buffer->reset();
436     int pid = zygote::forkApp(env, /* no pipe FDs */ -1, -1, session_socket_fds,
437                               /*args_known=*/ true, /*is_priority_fork=*/ true,
438                               /*purge=*/ first_time);
439     if (pid == 0) {
440       return JNI_TRUE;
441     }
442     // We're in the parent. Write big-endian pid, followed by a boolean.
443     char pid_buf[5];
444     int tmp_pid = pid;
445     for (int i = 3; i >= 0; --i) {
446       pid_buf[i] = tmp_pid & 0xff;
447       tmp_pid >>= 8;
448     }
449     pid_buf[4] = 0;  // Process is not wrapped.
450     int res = TEMP_FAILURE_RETRY(write(session_socket, pid_buf, 5));
451     if (res != 5) {
452       if (res == -1) {
453         (first_time ? fail_fn_1 : fail_fn_n)
454             (CREATE_ERROR("Pid write error %d: %s", errno, strerror(errno)));
455       } else {
456         (first_time ? fail_fn_1 : fail_fn_n)
457             (CREATE_ERROR("Write unexpectedly returned short: %d < 5", res));
458       }
459     }
460     for (;;) {
461       bool valid_session_socket = true;
462       // Clear buffer and get count from next command.
463       n_buffer->clear();
464       // Poll isn't strictly necessary for now. But without it, disconnect is hard to detect.
465       int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */));
466       if (poll_res < 0) {
467         fail_fn_z(CREATE_ERROR("Poll failed: %d: %s", errno, strerror(errno)));
468       }
469       if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) {
470         if (n_buffer->getCount(fail_fn_z) != 0) {
471           break;
472         } else {
473           // Session socket was disconnected
474           valid_session_socket = false;
475           close(session_socket);
476         }
477       } else if (poll_res == 0 || (fd_structs[ZYGOTE_IDX].revents & POLLIN) == 0) {
478         fail_fn_z(
479             CREATE_ERROR("Poll returned with no descriptors ready! Poll returned %d", poll_res));
480       }
481       int new_fd = -1;
482       do {
483         // We've now seen either a disconnect or connect request.
484         new_fd = TEMP_FAILURE_RETRY(accept(zygote_socket_fd, nullptr, nullptr));
485         if (new_fd == -1) {
486           fail_fn_z(CREATE_ERROR("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno)));
487         }
488         uid_t newPeerUid = getSocketPeerUid(new_fd, fail_fn_1);
489         if (newPeerUid != static_cast<uid_t>(expected_uid)) {
490           ALOGW("Dropping new connection with a mismatched uid %d\n", newPeerUid);
491           close(new_fd);
492           new_fd = -1;
493         } else {
494           // If we still have a valid session socket, close it now
495           if (valid_session_socket) {
496               close(session_socket);
497           }
498           valid_session_socket = true;
499         }
500       } while (!valid_session_socket);
501 
502       // At this point we either have a valid new connection (new_fd > 0), or
503       // an existing session socket we can poll on
504       if (new_fd == -1) {
505         // The new connection wasn't valid, and we still have an old one; retry polling
506         continue;
507       }
508       if (new_fd != session_socket) {
509         // Move new_fd back to the old value, so that we don't have to change Java-level data
510         // structures to reflect a change. This implicitly closes the old one.
511         if (TEMP_FAILURE_RETRY(dup2(new_fd, session_socket)) != session_socket) {
512           fail_fn_z(CREATE_ERROR("Failed to move fd %d to %d: %s",
513                                  new_fd, session_socket, strerror(errno)));
514         }
515         close(new_fd);  //  On Linux, fd is closed even if EINTR is returned.
516       }
517       // If we ever return, we effectively reuse the old Java ZygoteConnection.
518       // None of its state needs to change.
519       if (setsockopt(session_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, timeout_size) != 0) {
520         fail_fn_z(CREATE_ERROR("Failed to set receive timeout for socket %d: %s",
521                                session_socket, strerror(errno)));
522       }
523       if (setsockopt(session_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, timeout_size) != 0) {
524         fail_fn_z(CREATE_ERROR("Failed to set send timeout for socket %d: %s",
525                                session_socket, strerror(errno)));
526       }
527     }
528     first_time = false;
529   } while (n_buffer->isSimpleForkCommand(minUid, fail_fn_n));
530   ALOGW("forkRepeatedly terminated due to non-simple command");
531   n_buffer->logState();
532   n_buffer->reset();
533   return JNI_FALSE;
534 }
535 
536 #define METHOD_NAME(m) com_android_internal_os_ZygoteCommandBuffer_ ## m
537 
538 static const JNINativeMethod gMethods[] = {
539         {"getNativeBuffer", "(I)J", (void *) METHOD_NAME(getNativeBuffer)},
540         {"freeNativeBuffer", "(J)V", (void *) METHOD_NAME(freeNativeBuffer)},
541         {"insert", "(JLjava/lang/String;)V", (void *) METHOD_NAME(insert)},
542         {"nativeNextArg", "(J)Ljava/lang/String;", (void *) METHOD_NAME(nativeNextArg)},
543         {"nativeReadFullyAndReset", "(J)V", (void *) METHOD_NAME(nativeReadFullyAndReset)},
544         {"nativeGetCount", "(J)I", (void *) METHOD_NAME(nativeGetCount)},
545         {"nativeForkRepeatedly", "(JIIILjava/lang/String;)Z",
546           (void *) METHOD_NAME(nativeForkRepeatedly)},
547 };
548 
register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv * env)549 int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv* env) {
550   return RegisterMethodsOrDie(env, "com/android/internal/os/ZygoteCommandBuffer", gMethods,
551                               NELEM(gMethods));
552 }
553 
554 }  // namespace android
555