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