1 /* 2 * Copyright (C) 2012-2014 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 <stdlib.h> 18 19 #include <private/android_filesystem_config.h> 20 21 #include "FlushCommand.h" 22 #include "LogBuffer.h" 23 #include "LogBufferElement.h" 24 #include "LogCommand.h" 25 #include "LogReader.h" 26 #include "LogTimes.h" 27 #include "LogUtils.h" 28 29 FlushCommand::FlushCommand(LogReader& reader, bool nonBlock, unsigned long tail, 30 unsigned int logMask, pid_t pid, log_time start, 31 uint64_t timeout) 32 : mReader(reader), 33 mNonBlock(nonBlock), 34 mTail(tail), 35 mLogMask(logMask), 36 mPid(pid), 37 mStart(start), 38 mTimeout((start != log_time::EPOCH) ? timeout : 0) { 39 } 40 41 // runSocketCommand is called once for every open client on the 42 // log reader socket. Here we manage and associated the reader 43 // client tracking and log region locks LastLogTimes list of 44 // LogTimeEntrys, and spawn a transitory per-client thread to 45 // work at filing data to the socket. 46 // 47 // global LogTimeEntry::wrlock() is used to protect access, 48 // reference counts are used to ensure that individual 49 // LogTimeEntry lifetime is managed when not protected. 50 void FlushCommand::runSocketCommand(SocketClient* client) { 51 LogTimeEntry* entry = NULL; 52 LastLogTimes& times = mReader.logbuf().mTimes; 53 54 LogTimeEntry::wrlock(); 55 LastLogTimes::iterator it = times.begin(); 56 while (it != times.end()) { 57 entry = (*it); 58 if (entry->mClient == client) { 59 if (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec) { 60 if (mReader.logbuf().isMonotonic()) { 61 LogTimeEntry::unlock(); 62 return; 63 } 64 // If the user changes the time in a gross manner that 65 // invalidates the timeout, fall through and trigger. 66 log_time now(CLOCK_REALTIME); 67 if (((entry->mEnd + entry->mTimeout) > now) && 68 (now > entry->mEnd)) { 69 LogTimeEntry::unlock(); 70 return; 71 } 72 } 73 entry->triggerReader_Locked(); 74 if (entry->runningReader_Locked()) { 75 LogTimeEntry::unlock(); 76 return; 77 } 78 entry->incRef_Locked(); 79 break; 80 } 81 it++; 82 } 83 84 if (it == times.end()) { 85 // Create LogTimeEntry in notifyNewLog() ? 86 if (mTail == (unsigned long)-1) { 87 LogTimeEntry::unlock(); 88 return; 89 } 90 entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, 91 mPid, mStart, mTimeout); 92 times.push_front(entry); 93 } 94 95 client->incRef(); 96 97 // release client and entry reference counts once done 98 entry->startReader_Locked(); 99 LogTimeEntry::unlock(); 100 } 101 102 bool FlushCommand::hasReadLogs(SocketClient* client) { 103 return clientHasLogCredentials(client); 104 } 105 106 static bool clientHasSecurityCredentials(SocketClient* client) { 107 return (client->getUid() == AID_SYSTEM) || (client->getGid() == AID_SYSTEM); 108 } 109 110 bool FlushCommand::hasSecurityLogs(SocketClient* client) { 111 return clientHasSecurityCredentials(client); 112 } 113