BufferQueueConsumer.cpp revision 8b640e6403de9dd328b2605c9f21b62d1d31e7d6
1/* 2 * Copyright 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 <inttypes.h> 18 19#define LOG_TAG "BufferQueueConsumer" 20#define ATRACE_TAG ATRACE_TAG_GRAPHICS 21//#define LOG_NDEBUG 0 22 23#include <gui/BufferItem.h> 24#include <gui/BufferQueueConsumer.h> 25#include <gui/BufferQueueCore.h> 26#include <gui/IConsumerListener.h> 27#include <gui/IProducerListener.h> 28 29#include <binder/IPCThreadState.h> 30#include <binder/PermissionCache.h> 31#include <private/android_filesystem_config.h> 32 33namespace android { 34 35BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) : 36 mCore(core), 37 mSlots(core->mSlots), 38 mConsumerName() {} 39 40BufferQueueConsumer::~BufferQueueConsumer() {} 41 42status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, 43 nsecs_t expectedPresent, uint64_t maxFrameNumber) { 44 ATRACE_CALL(); 45 46 int numDroppedBuffers = 0; 47 sp<IProducerListener> listener; 48 { 49 Mutex::Autolock lock(mCore->mMutex); 50 51 // Check that the consumer doesn't currently have the maximum number of 52 // buffers acquired. We allow the max buffer count to be exceeded by one 53 // buffer so that the consumer can successfully set up the newly acquired 54 // buffer before releasing the old one. 55 int numAcquiredBuffers = 0; 56 for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { 57 if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { 58 ++numAcquiredBuffers; 59 } 60 } 61 if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { 62 BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", 63 numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); 64 return INVALID_OPERATION; 65 } 66 67 // Check if the queue is empty. 68 // In asynchronous mode the list is guaranteed to be one buffer deep, 69 // while in synchronous mode we use the oldest buffer. 70 if (mCore->mQueue.empty()) { 71 return NO_BUFFER_AVAILABLE; 72 } 73 74 BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); 75 76 // If expectedPresent is specified, we may not want to return a buffer yet. 77 // If it's specified and there's more than one buffer queued, we may want 78 // to drop a buffer. 79 if (expectedPresent != 0) { 80 const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second 81 82 // The 'expectedPresent' argument indicates when the buffer is expected 83 // to be presented on-screen. If the buffer's desired present time is 84 // earlier (less) than expectedPresent -- meaning it will be displayed 85 // on time or possibly late if we show it as soon as possible -- we 86 // acquire and return it. If we don't want to display it until after the 87 // expectedPresent time, we return PRESENT_LATER without acquiring it. 88 // 89 // To be safe, we don't defer acquisition if expectedPresent is more 90 // than one second in the future beyond the desired present time 91 // (i.e., we'd be holding the buffer for a long time). 92 // 93 // NOTE: Code assumes monotonic time values from the system clock 94 // are positive. 95 96 // Start by checking to see if we can drop frames. We skip this check if 97 // the timestamps are being auto-generated by Surface. If the app isn't 98 // generating timestamps explicitly, it probably doesn't want frames to 99 // be discarded based on them. 100 while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { 101 const BufferItem& bufferItem(mCore->mQueue[1]); 102 103 // If dropping entry[0] would leave us with a buffer that the 104 // consumer is not yet ready for, don't drop it. 105 if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) { 106 break; 107 } 108 109 // If entry[1] is timely, drop entry[0] (and repeat). We apply an 110 // additional criterion here: we only drop the earlier buffer if our 111 // desiredPresent falls within +/- 1 second of the expected present. 112 // Otherwise, bogus desiredPresent times (e.g., 0 or a small 113 // relative timestamp), which normally mean "ignore the timestamp 114 // and acquire immediately", would cause us to drop frames. 115 // 116 // We may want to add an additional criterion: don't drop the 117 // earlier buffer if entry[1]'s fence hasn't signaled yet. 118 nsecs_t desiredPresent = bufferItem.mTimestamp; 119 if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || 120 desiredPresent > expectedPresent) { 121 // This buffer is set to display in the near future, or 122 // desiredPresent is garbage. Either way we don't want to drop 123 // the previous buffer just to get this on the screen sooner. 124 BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" 125 PRId64 " (%" PRId64 ") now=%" PRId64, 126 desiredPresent, expectedPresent, 127 desiredPresent - expectedPresent, 128 systemTime(CLOCK_MONOTONIC)); 129 break; 130 } 131 132 BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 133 " size=%zu", 134 desiredPresent, expectedPresent, mCore->mQueue.size()); 135 if (mCore->stillTracking(front)) { 136 // Front buffer is still in mSlots, so mark the slot as free 137 mSlots[front->mSlot].mBufferState = BufferSlot::FREE; 138 mCore->mFreeBuffers.push_back(front->mSlot); 139 listener = mCore->mConnectedProducerListener; 140 ++numDroppedBuffers; 141 } 142 mCore->mQueue.erase(front); 143 front = mCore->mQueue.begin(); 144 } 145 146 // See if the front buffer is ready to be acquired 147 nsecs_t desiredPresent = front->mTimestamp; 148 bool bufferIsDue = desiredPresent <= expectedPresent || 149 desiredPresent > expectedPresent + MAX_REASONABLE_NSEC; 150 bool consumerIsReady = maxFrameNumber > 0 ? 151 front->mFrameNumber <= maxFrameNumber : true; 152 if (!bufferIsDue || !consumerIsReady) { 153 BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 154 " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64 155 " consumer=%" PRIu64, 156 desiredPresent, expectedPresent, 157 desiredPresent - expectedPresent, 158 systemTime(CLOCK_MONOTONIC), 159 front->mFrameNumber, maxFrameNumber); 160 return PRESENT_LATER; 161 } 162 163 BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " 164 "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, 165 desiredPresent - expectedPresent, 166 systemTime(CLOCK_MONOTONIC)); 167 } 168 169 int slot = front->mSlot; 170 *outBuffer = *front; 171 ATRACE_BUFFER_INDEX(slot); 172 173 BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", 174 slot, front->mFrameNumber, front->mGraphicBuffer->handle); 175 // If the front buffer is still being tracked, update its slot state 176 if (mCore->stillTracking(front)) { 177 mSlots[slot].mAcquireCalled = true; 178 mSlots[slot].mNeedsCleanupOnRelease = false; 179 mSlots[slot].mBufferState = BufferSlot::ACQUIRED; 180 mSlots[slot].mFence = Fence::NO_FENCE; 181 } 182 183 // If the buffer has previously been acquired by the consumer, set 184 // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer 185 // on the consumer side 186 if (outBuffer->mAcquireCalled) { 187 outBuffer->mGraphicBuffer = NULL; 188 } 189 190 mCore->mQueue.erase(front); 191 192 // We might have freed a slot while dropping old buffers, or the producer 193 // may be blocked waiting for the number of buffers in the queue to 194 // decrease. 195 mCore->mDequeueCondition.broadcast(); 196 197 ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); 198 199 mCore->validateConsistencyLocked(); 200 } 201 202 if (listener != NULL) { 203 for (int i = 0; i < numDroppedBuffers; ++i) { 204 listener->onBufferReleased(); 205 } 206 } 207 208 return NO_ERROR; 209} 210 211status_t BufferQueueConsumer::detachBuffer(int slot) { 212 ATRACE_CALL(); 213 ATRACE_BUFFER_INDEX(slot); 214 BQ_LOGV("detachBuffer(C): slot %d", slot); 215 Mutex::Autolock lock(mCore->mMutex); 216 217 if (mCore->mIsAbandoned) { 218 BQ_LOGE("detachBuffer(C): BufferQueue has been abandoned"); 219 return NO_INIT; 220 } 221 222 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { 223 BQ_LOGE("detachBuffer(C): slot index %d out of range [0, %d)", 224 slot, BufferQueueDefs::NUM_BUFFER_SLOTS); 225 return BAD_VALUE; 226 } else if (mSlots[slot].mBufferState != BufferSlot::ACQUIRED) { 227 BQ_LOGE("detachBuffer(C): slot %d is not owned by the consumer " 228 "(state = %d)", slot, mSlots[slot].mBufferState); 229 return BAD_VALUE; 230 } 231 232 mCore->freeBufferLocked(slot); 233 mCore->mDequeueCondition.broadcast(); 234 mCore->validateConsistencyLocked(); 235 236 return NO_ERROR; 237} 238 239status_t BufferQueueConsumer::attachBuffer(int* outSlot, 240 const sp<android::GraphicBuffer>& buffer) { 241 ATRACE_CALL(); 242 243 if (outSlot == NULL) { 244 BQ_LOGE("attachBuffer(P): outSlot must not be NULL"); 245 return BAD_VALUE; 246 } else if (buffer == NULL) { 247 BQ_LOGE("attachBuffer(P): cannot attach NULL buffer"); 248 return BAD_VALUE; 249 } 250 251 Mutex::Autolock lock(mCore->mMutex); 252 253 // Make sure we don't have too many acquired buffers 254 int numAcquiredBuffers = 0; 255 for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { 256 if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { 257 ++numAcquiredBuffers; 258 } 259 } 260 261 if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { 262 BQ_LOGE("attachBuffer(P): max acquired buffer count reached: %d " 263 "(max %d)", numAcquiredBuffers, 264 mCore->mMaxAcquiredBufferCount); 265 return INVALID_OPERATION; 266 } 267 268 if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { 269 BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " 270 "[queue %u]", buffer->getGenerationNumber(), 271 mCore->mGenerationNumber); 272 return BAD_VALUE; 273 } 274 275 // Find a free slot to put the buffer into 276 int found = BufferQueueCore::INVALID_BUFFER_SLOT; 277 if (!mCore->mFreeSlots.empty()) { 278 auto slot = mCore->mFreeSlots.begin(); 279 found = *slot; 280 mCore->mFreeSlots.erase(slot); 281 } else if (!mCore->mFreeBuffers.empty()) { 282 found = mCore->mFreeBuffers.front(); 283 mCore->mFreeBuffers.remove(found); 284 } 285 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { 286 BQ_LOGE("attachBuffer(P): could not find free buffer slot"); 287 return NO_MEMORY; 288 } 289 290 *outSlot = found; 291 ATRACE_BUFFER_INDEX(*outSlot); 292 BQ_LOGV("attachBuffer(C): returning slot %d", *outSlot); 293 294 mSlots[*outSlot].mGraphicBuffer = buffer; 295 mSlots[*outSlot].mBufferState = BufferSlot::ACQUIRED; 296 mSlots[*outSlot].mAttachedByConsumer = true; 297 mSlots[*outSlot].mNeedsCleanupOnRelease = false; 298 mSlots[*outSlot].mFence = Fence::NO_FENCE; 299 mSlots[*outSlot].mFrameNumber = 0; 300 301 // mAcquireCalled tells BufferQueue that it doesn't need to send a valid 302 // GraphicBuffer pointer on the next acquireBuffer call, which decreases 303 // Binder traffic by not un/flattening the GraphicBuffer. However, it 304 // requires that the consumer maintain a cached copy of the slot <--> buffer 305 // mappings, which is why the consumer doesn't need the valid pointer on 306 // acquire. 307 // 308 // The StreamSplitter is one of the primary users of the attach/detach 309 // logic, and while it is running, all buffers it acquires are immediately 310 // detached, and all buffers it eventually releases are ones that were 311 // attached (as opposed to having been obtained from acquireBuffer), so it 312 // doesn't make sense to maintain the slot/buffer mappings, which would 313 // become invalid for every buffer during detach/attach. By setting this to 314 // false, the valid GraphicBuffer pointer will always be sent with acquire 315 // for attached buffers. 316 mSlots[*outSlot].mAcquireCalled = false; 317 318 mCore->validateConsistencyLocked(); 319 320 return NO_ERROR; 321} 322 323status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, 324 const sp<Fence>& releaseFence, EGLDisplay eglDisplay, 325 EGLSyncKHR eglFence) { 326 ATRACE_CALL(); 327 ATRACE_BUFFER_INDEX(slot); 328 329 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || 330 releaseFence == NULL) { 331 BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot, 332 releaseFence.get()); 333 return BAD_VALUE; 334 } 335 336 sp<IProducerListener> listener; 337 { // Autolock scope 338 Mutex::Autolock lock(mCore->mMutex); 339 340 // If the frame number has changed because the buffer has been reallocated, 341 // we can ignore this releaseBuffer for the old buffer 342 if (frameNumber != mSlots[slot].mFrameNumber) { 343 return STALE_BUFFER_SLOT; 344 } 345 346 // Make sure this buffer hasn't been queued while acquired by the consumer 347 BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); 348 while (current != mCore->mQueue.end()) { 349 if (current->mSlot == slot) { 350 BQ_LOGE("releaseBuffer: buffer slot %d pending release is " 351 "currently queued", slot); 352 return BAD_VALUE; 353 } 354 ++current; 355 } 356 357 if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { 358 mSlots[slot].mEglDisplay = eglDisplay; 359 mSlots[slot].mEglFence = eglFence; 360 mSlots[slot].mFence = releaseFence; 361 mSlots[slot].mBufferState = BufferSlot::FREE; 362 mCore->mFreeBuffers.push_back(slot); 363 listener = mCore->mConnectedProducerListener; 364 BQ_LOGV("releaseBuffer: releasing slot %d", slot); 365 } else if (mSlots[slot].mNeedsCleanupOnRelease) { 366 BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d " 367 "(state = %d)", slot, mSlots[slot].mBufferState); 368 mSlots[slot].mNeedsCleanupOnRelease = false; 369 return STALE_BUFFER_SLOT; 370 } else { 371 BQ_LOGE("releaseBuffer: attempted to release buffer slot %d " 372 "but its state was %d", slot, mSlots[slot].mBufferState); 373 return BAD_VALUE; 374 } 375 376 mCore->mDequeueCondition.broadcast(); 377 mCore->validateConsistencyLocked(); 378 } // Autolock scope 379 380 // Call back without lock held 381 if (listener != NULL) { 382 listener->onBufferReleased(); 383 } 384 385 return NO_ERROR; 386} 387 388status_t BufferQueueConsumer::connect( 389 const sp<IConsumerListener>& consumerListener, bool controlledByApp) { 390 ATRACE_CALL(); 391 392 if (consumerListener == NULL) { 393 BQ_LOGE("connect(C): consumerListener may not be NULL"); 394 return BAD_VALUE; 395 } 396 397 BQ_LOGV("connect(C): controlledByApp=%s", 398 controlledByApp ? "true" : "false"); 399 400 Mutex::Autolock lock(mCore->mMutex); 401 402 if (mCore->mIsAbandoned) { 403 BQ_LOGE("connect(C): BufferQueue has been abandoned"); 404 return NO_INIT; 405 } 406 407 mCore->mConsumerListener = consumerListener; 408 mCore->mConsumerControlledByApp = controlledByApp; 409 410 return NO_ERROR; 411} 412 413status_t BufferQueueConsumer::disconnect() { 414 ATRACE_CALL(); 415 416 BQ_LOGV("disconnect(C)"); 417 418 Mutex::Autolock lock(mCore->mMutex); 419 420 if (mCore->mConsumerListener == NULL) { 421 BQ_LOGE("disconnect(C): no consumer is connected"); 422 return BAD_VALUE; 423 } 424 425 mCore->mIsAbandoned = true; 426 mCore->mConsumerListener = NULL; 427 mCore->mQueue.clear(); 428 mCore->freeAllBuffersLocked(); 429 mCore->mDequeueCondition.broadcast(); 430 return NO_ERROR; 431} 432 433status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { 434 ATRACE_CALL(); 435 436 if (outSlotMask == NULL) { 437 BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL"); 438 return BAD_VALUE; 439 } 440 441 Mutex::Autolock lock(mCore->mMutex); 442 443 if (mCore->mIsAbandoned) { 444 BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned"); 445 return NO_INIT; 446 } 447 448 uint64_t mask = 0; 449 for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { 450 if (!mSlots[s].mAcquireCalled) { 451 mask |= (1ULL << s); 452 } 453 } 454 455 // Remove from the mask queued buffers for which acquire has been called, 456 // since the consumer will not receive their buffer addresses and so must 457 // retain their cached information 458 BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); 459 while (current != mCore->mQueue.end()) { 460 if (current->mAcquireCalled) { 461 mask &= ~(1ULL << current->mSlot); 462 } 463 ++current; 464 } 465 466 BQ_LOGV("getReleasedBuffers: returning mask %#" PRIx64, mask); 467 *outSlotMask = mask; 468 return NO_ERROR; 469} 470 471status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, 472 uint32_t height) { 473 ATRACE_CALL(); 474 475 if (width == 0 || height == 0) { 476 BQ_LOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u " 477 "height=%u)", width, height); 478 return BAD_VALUE; 479 } 480 481 BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height); 482 483 Mutex::Autolock lock(mCore->mMutex); 484 mCore->mDefaultWidth = width; 485 mCore->mDefaultHeight = height; 486 return NO_ERROR; 487} 488 489status_t BufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) { 490 ATRACE_CALL(); 491 Mutex::Autolock lock(mCore->mMutex); 492 return mCore->setDefaultMaxBufferCountLocked(bufferCount); 493} 494 495status_t BufferQueueConsumer::disableAsyncBuffer() { 496 ATRACE_CALL(); 497 498 Mutex::Autolock lock(mCore->mMutex); 499 500 if (mCore->mConsumerListener != NULL) { 501 BQ_LOGE("disableAsyncBuffer: consumer already connected"); 502 return INVALID_OPERATION; 503 } 504 505 BQ_LOGV("disableAsyncBuffer"); 506 mCore->mUseAsyncBuffer = false; 507 return NO_ERROR; 508} 509 510status_t BufferQueueConsumer::setMaxAcquiredBufferCount( 511 int maxAcquiredBuffers) { 512 ATRACE_CALL(); 513 514 if (maxAcquiredBuffers < 1 || 515 maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) { 516 BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d", 517 maxAcquiredBuffers); 518 return BAD_VALUE; 519 } 520 521 Mutex::Autolock lock(mCore->mMutex); 522 523 if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { 524 BQ_LOGE("setMaxAcquiredBufferCount: producer is already connected"); 525 return INVALID_OPERATION; 526 } 527 528 BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); 529 mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; 530 return NO_ERROR; 531} 532 533void BufferQueueConsumer::setConsumerName(const String8& name) { 534 ATRACE_CALL(); 535 BQ_LOGV("setConsumerName: '%s'", name.string()); 536 Mutex::Autolock lock(mCore->mMutex); 537 mCore->mConsumerName = name; 538 mConsumerName = name; 539} 540 541status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { 542 ATRACE_CALL(); 543 BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat); 544 Mutex::Autolock lock(mCore->mMutex); 545 mCore->mDefaultBufferFormat = defaultFormat; 546 return NO_ERROR; 547} 548 549status_t BufferQueueConsumer::setDefaultBufferDataSpace( 550 android_dataspace defaultDataSpace) { 551 ATRACE_CALL(); 552 BQ_LOGV("setDefaultBufferDataSpace: %u", defaultDataSpace); 553 Mutex::Autolock lock(mCore->mMutex); 554 mCore->mDefaultBufferDataSpace = defaultDataSpace; 555 return NO_ERROR; 556} 557 558status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { 559 ATRACE_CALL(); 560 BQ_LOGV("setConsumerUsageBits: %#x", usage); 561 Mutex::Autolock lock(mCore->mMutex); 562 mCore->mConsumerUsageBits = usage; 563 return NO_ERROR; 564} 565 566status_t BufferQueueConsumer::setTransformHint(uint32_t hint) { 567 ATRACE_CALL(); 568 BQ_LOGV("setTransformHint: %#x", hint); 569 Mutex::Autolock lock(mCore->mMutex); 570 mCore->mTransformHint = hint; 571 return NO_ERROR; 572} 573 574sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const { 575 return mCore->mSidebandStream; 576} 577 578void BufferQueueConsumer::dump(String8& result, const char* prefix) const { 579 const IPCThreadState* ipc = IPCThreadState::self(); 580 const pid_t pid = ipc->getCallingPid(); 581 const uid_t uid = ipc->getCallingUid(); 582 if ((uid != AID_SHELL) 583 && !PermissionCache::checkPermission(String16( 584 "android.permission.DUMP"), pid, uid)) { 585 result.appendFormat("Permission Denial: can't dump BufferQueueConsumer " 586 "from pid=%d, uid=%d\n", pid, uid); 587 } else { 588 mCore->dump(result, prefix); 589 } 590} 591 592} // namespace android 593