1 /* 2 * Copyright (C) 2013-2018 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 #ifndef ANDROID_SERVERS_CAMERA3_STREAM_H 18 #define ANDROID_SERVERS_CAMERA3_STREAM_H 19 20 #include <gui/Surface.h> 21 #include <utils/RefBase.h> 22 #include <utils/String8.h> 23 #include <utils/String16.h> 24 #include <utils/List.h> 25 26 #include "utils/LatencyHistogram.h" 27 #include "Camera3StreamBufferListener.h" 28 #include "Camera3StreamInterface.h" 29 30 namespace android { 31 32 namespace camera3 { 33 34 /** 35 * A class for managing a single stream of input or output data from the camera 36 * device. 37 * 38 * The stream has an internal state machine to track whether it's 39 * connected/configured/etc. 40 * 41 * States: 42 * 43 * STATE_ERROR: A serious error has occurred, stream is unusable. Outstanding 44 * buffers may still be returned. 45 * 46 * STATE_CONSTRUCTED: The stream is ready for configuration, but buffers cannot 47 * be gotten yet. Not connected to any endpoint, no buffers are registered 48 * with the HAL. 49 * 50 * STATE_IN_CONFIG: Configuration has started, but not yet concluded. During this 51 * time, the usage, max_buffers, and priv fields of camera_stream returned by 52 * startConfiguration() may be modified. 53 * 54 * STATE_IN_RE_CONFIG: Configuration has started, and the stream has been 55 * configured before. Need to track separately from IN_CONFIG to avoid 56 * re-registering buffers with HAL. 57 * 58 * STATE_CONFIGURED: Stream is configured, and has registered buffers with the 59 * HAL (if necessary). The stream's getBuffer/returnBuffer work. The priv 60 * pointer may still be modified. 61 * 62 * STATE_PREPARING: The stream's buffers are being pre-allocated for use. On 63 * older HALs, this is done as part of configuration, but in newer HALs 64 * buffers may be allocated at time of first use. But some use cases require 65 * buffer allocation upfront, to minmize disruption due to lengthy allocation 66 * duration. In this state, only prepareNextBuffer() and cancelPrepare() 67 * may be called. 68 * 69 * STATE_IN_IDLE: This is a temporary state only intended to be used for input 70 * streams and only for the case where we need to re-configure the camera device 71 * while the input stream has an outstanding buffer. All other streams should not 72 * be able to switch to this state. For them this is invalid and should be handled 73 * as an unknown state. 74 * 75 * Transition table: 76 * 77 * <none> => STATE_CONSTRUCTED: 78 * When constructed with valid arguments 79 * <none> => STATE_ERROR: 80 * When constructed with invalid arguments 81 * STATE_CONSTRUCTED => STATE_IN_CONFIG: 82 * When startConfiguration() is called 83 * STATE_IN_CONFIG => STATE_CONFIGURED: 84 * When finishConfiguration() is called 85 * STATE_IN_CONFIG => STATE_ERROR: 86 * When finishConfiguration() fails to allocate or register buffers. 87 * STATE_CONFIGURED => STATE_IN_RE_CONFIG: * 88 * When startConfiguration() is called again, after making sure stream is 89 * idle with waitUntilIdle(). 90 * STATE_IN_RE_CONFIG => STATE_CONFIGURED: 91 * When finishConfiguration() is called. 92 * STATE_IN_RE_CONFIG => STATE_ERROR: 93 * When finishConfiguration() fails to allocate or register buffers. 94 * STATE_CONFIGURED => STATE_CONSTRUCTED: 95 * When disconnect() is called after making sure stream is idle with 96 * waitUntilIdle(). 97 * STATE_CONFIGURED => STATE_PREPARING: 98 * When startPrepare is called before the stream has a buffer 99 * queued back into it for the first time. 100 * STATE_PREPARING => STATE_CONFIGURED: 101 * When sufficient prepareNextBuffer calls have been made to allocate 102 * all stream buffers, or cancelPrepare is called. 103 * STATE_CONFIGURED => STATE_ABANDONED: 104 * When the buffer queue of the stream is abandoned. 105 * STATE_CONFIGURED => STATE_IN_IDLE: 106 * Only for an input stream which has an outstanding buffer. 107 * STATE_IN_IDLE => STATE_CONFIGURED: 108 * After the internal re-configuration, the input should revert back to 109 * the configured state. 110 * 111 * Status Tracking: 112 * Each stream is tracked by StatusTracker as a separate component, 113 * depending on the handed out buffer count. The state must be STATE_CONFIGURED 114 * in order for the component to be marked. 115 * 116 * It's marked in one of two ways: 117 * 118 * - ACTIVE: One or more buffers have been handed out (with #getBuffer). 119 * - IDLE: All buffers have been returned (with #returnBuffer), and their 120 * respective release_fence(s) have been signaled. The only exception to this 121 * rule is an input stream that moves to "STATE_IN_IDLE" during internal 122 * re-configuration. 123 * 124 * A typical use case is output streams. When the HAL has any buffers 125 * dequeued, the stream is marked ACTIVE. When the HAL returns all buffers 126 * (e.g. if no capture requests are active), the stream is marked IDLE. 127 * In this use case, the app consumer does not affect the component status. 128 * 129 */ 130 class Camera3Stream : 131 protected camera_stream, 132 public virtual Camera3StreamInterface, 133 public virtual RefBase { 134 public: 135 136 virtual ~Camera3Stream(); 137 138 static Camera3Stream* cast(camera_stream *stream); 139 static const Camera3Stream* cast(const camera_stream *stream); 140 141 // Queue corresponding HDR metadata to given native window. 142 static void queueHDRMetadata(buffer_handle_t buffer, sp<ANativeWindow>& anw, 143 int64_t dynamicRangeProfile); 144 145 /** 146 * Get the stream's ID 147 */ 148 int getId() const; 149 150 /** 151 * Get the output stream set id. 152 */ 153 int getStreamSetId() const; 154 /** 155 * Is this stream part of a multi-resolution stream set 156 */ 157 bool isMultiResolution() const; 158 /** 159 * Get the HAL stream group id for a multi-resolution stream set 160 */ 161 int getHalStreamGroupId() const; 162 163 /** 164 * Get the stream's dimensions and format 165 */ 166 uint32_t getWidth() const; 167 uint32_t getHeight() const; 168 int getFormat() const; 169 android_dataspace getDataSpace() const; 170 int32_t getColorSpace() const; 171 uint64_t getUsage() const; 172 void setUsage(uint64_t usage); 173 void setFormatOverride(bool formatOverriden); 174 bool isFormatOverridden() const; 175 int getOriginalFormat() const; 176 int64_t getDynamicRangeProfile() const; 177 void setDataSpaceOverride(bool dataSpaceOverriden); 178 bool isDataSpaceOverridden() const; 179 android_dataspace getOriginalDataSpace() const; 180 int getMaxHalBuffers() const; 181 const String8& physicalCameraId() const; 182 int64_t getStreamUseCase() const; 183 int getTimestampBase() const; 184 bool isDeviceTimeBaseRealtime() const; 185 186 void setOfflineProcessingSupport(bool) override; 187 bool getOfflineProcessingSupport() const override; 188 asHalStream()189 camera_stream* asHalStream() override { 190 return this; 191 } 192 193 /** 194 * Start the stream configuration process. Returns a handle to the stream's 195 * information to be passed into the HAL device's configure_streams call. 196 * 197 * Until finishConfiguration() is called, no other methods on the stream may be 198 * called. The usage and max_buffers fields of camera_stream may be modified 199 * between start/finishConfiguration, but may not be changed after that. 200 * 201 * Returns NULL in case of error starting configuration. 202 */ 203 camera_stream* startConfiguration(); 204 205 /** 206 * Check if the stream is mid-configuration (start has been called, but not 207 * finish). Used for lazy completion of configuration. 208 */ 209 bool isConfiguring() const; 210 211 /** 212 * Completes the stream configuration process. The stream information 213 * structure returned by startConfiguration() may no longer be modified 214 * after this call, but can still be read until the destruction of the 215 * stream. 216 * 217 * streamReconfigured: set to true when a stream is being reconfigured. 218 * 219 * Returns: 220 * OK on a successful configuration 221 * NO_INIT in case of a serious error from the HAL device 222 * NO_MEMORY in case of an error registering buffers 223 * INVALID_OPERATION in case connecting to the consumer failed or consumer 224 * doesn't exist yet. 225 */ 226 status_t finishConfiguration(/*out*/bool* streamReconfigured = nullptr); 227 228 /** 229 * Cancels the stream configuration process. This returns the stream to the 230 * initial state, allowing it to be configured again later. 231 * This is done if the HAL rejects the proposed combined stream configuration 232 */ 233 status_t cancelConfiguration(); 234 235 /** 236 * Determine whether the stream has already become in-use (has received 237 * a valid filled buffer), which determines if a stream can still have 238 * prepareNextBuffer called on it. 239 */ 240 bool isUnpreparable(); 241 242 /** 243 * Mark the stream as unpreparable. 244 */ 245 void markUnpreparable() override; 246 247 /** 248 * Start stream preparation. May only be called in the CONFIGURED state, 249 * when no valid buffers have yet been returned to this stream. Prepares 250 * up to maxCount buffers, or the maximum number of buffers needed by the 251 * pipeline if maxCount is ALLOCATE_PIPELINE_MAX. 252 * 253 * If no prepartion is necessary, returns OK and does not transition to 254 * PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions 255 * to PREPARING. 256 * 257 * This call performs no allocation, so is quick to call. 258 * 259 * blockRequest specifies whether prepare will block upcoming capture 260 * request. This flag should only be set to false if the caller guarantees 261 * the whole buffer preparation process is done before capture request 262 * comes in. 263 * 264 * Returns: 265 * OK if no more buffers need to be preallocated 266 * NOT_ENOUGH_DATA if calls to prepareNextBuffer are needed to finish 267 * buffer pre-allocation, and transitions to the PREPARING state. 268 * NO_INIT in case of a serious error from the HAL device 269 * INVALID_OPERATION if called when not in CONFIGURED state, or a 270 * valid buffer has already been returned to this stream. 271 */ 272 status_t startPrepare(int maxCount, bool blockRequest); 273 274 /** 275 * Check if the request on a stream is blocked by prepare. 276 */ 277 bool isBlockedByPrepare() const; 278 279 /** 280 * Continue stream buffer preparation by allocating the next 281 * buffer for this stream. May only be called in the PREPARED state. 282 * 283 * Returns OK and transitions to the CONFIGURED state if all buffers 284 * are allocated after the call concludes. Otherwise returns NOT_ENOUGH_DATA. 285 * 286 * This call allocates one buffer, which may take several milliseconds for 287 * large buffers. 288 * 289 * Returns: 290 * OK if no more buffers need to be preallocated, and transitions 291 * to the CONFIGURED state. 292 * NOT_ENOUGH_DATA if more calls to prepareNextBuffer are needed to finish 293 * buffer pre-allocation. 294 * NO_INIT in case of a serious error from the HAL device 295 * INVALID_OPERATION if called when not in CONFIGURED state, or a 296 * valid buffer has already been returned to this stream. 297 */ 298 status_t prepareNextBuffer(); 299 300 /** 301 * Cancel stream preparation early. In case allocation needs to be 302 * stopped, this method transitions the stream back to the CONFIGURED state. 303 * Buffers that have been allocated with prepareNextBuffer remain that way, 304 * but a later use of prepareNextBuffer will require just as many 305 * calls as if the earlier prepare attempt had not existed. 306 * 307 * Returns: 308 * OK if cancellation succeeded, and transitions to the CONFIGURED state 309 * INVALID_OPERATION if not in the PREPARING state 310 * NO_INIT in case of a serious error from the HAL device 311 */ 312 status_t cancelPrepare(); 313 314 /** 315 * Tear down memory for this stream. This frees all unused gralloc buffers 316 * allocated for this stream, but leaves it ready for operation afterward. 317 * 318 * May only be called in the CONFIGURED state, and keeps the stream in 319 * the CONFIGURED state. 320 * 321 * Returns: 322 * OK if teardown succeeded. 323 * INVALID_OPERATION if not in the CONFIGURED state 324 * NO_INIT in case of a serious error from the HAL device 325 */ 326 status_t tearDown(); 327 328 /** 329 * Fill in the camera_stream_buffer with the next valid buffer for this 330 * stream, to hand over to the HAL. 331 * 332 * Multiple surfaces could share the same HAL stream, but a request may 333 * be only for a subset of surfaces. In this case, the 334 * Camera3StreamInterface object needs the surface ID information to acquire 335 * buffers for those surfaces. 336 * 337 * This method may only be called once finishConfiguration has been called. 338 * For bidirectional streams, this method applies to the output-side 339 * buffers. 340 * 341 */ 342 status_t getBuffer(camera_stream_buffer *buffer, 343 nsecs_t waitBufferTimeout, 344 const std::vector<size_t>& surface_ids = std::vector<size_t>()); 345 346 /** 347 * Similar to getBuffer() except this method fills multiple buffers. 348 */ 349 status_t getBuffers(std::vector<OutstandingBuffer>* buffers, 350 nsecs_t waitBufferTimeout); 351 352 /** 353 * Return a buffer to the stream after use by the HAL. 354 * 355 * Multiple surfaces could share the same HAL stream, but a request may 356 * be only for a subset of surfaces. In this case, the 357 * Camera3StreamInterface object needs the surface ID information to attach 358 * buffers for those surfaces. 359 * 360 * This method may only be called for buffers provided by getBuffer(). 361 * For bidirectional streams, this method applies to the output-side buffers 362 */ 363 status_t returnBuffer(const camera_stream_buffer &buffer, 364 nsecs_t timestamp, nsecs_t readoutTimestamp, bool timestampIncreasing, 365 const std::vector<size_t>& surface_ids = std::vector<size_t>(), 366 uint64_t frameNumber = 0, int32_t transform = -1); 367 368 /** 369 * Fill in the camera_stream_buffer with the next valid buffer for this 370 * stream, to hand over to the HAL. 371 * 372 * This method may only be called once finishConfiguration has been called. 373 * For bidirectional streams, this method applies to the input-side 374 * buffers. 375 * 376 * This method also returns the size of the returned input buffer. 377 * 378 * Normally this call will block until the handed out buffer count is less than the stream 379 * max buffer count; if respectHalLimit is set to false, this is ignored. 380 */ 381 status_t getInputBuffer(camera_stream_buffer *buffer, 382 Size* size, bool respectHalLimit = true); 383 384 /** 385 * Return a buffer to the stream after use by the HAL. 386 * 387 * This method may only be called for buffers provided by getBuffer(). 388 * For bidirectional streams, this method applies to the input-side buffers 389 */ 390 status_t returnInputBuffer(const camera_stream_buffer &buffer); 391 392 // get the buffer producer of the input buffer queue. 393 // only apply to input streams. 394 status_t getInputBufferProducer(sp<IGraphicBufferProducer> *producer); 395 396 /** 397 * Whether any of the stream's buffers are currently in use by the HAL, 398 * including buffers that have been returned but not yet had their 399 * release fence signaled. 400 */ 401 bool hasOutstandingBuffers() const; 402 403 /** 404 * Get number of buffers currently handed out to HAL 405 */ 406 size_t getOutstandingBuffersCount() const; 407 408 enum { 409 TIMEOUT_NEVER = -1 410 }; 411 412 /** 413 * Set the status tracker to notify about idle transitions 414 */ 415 virtual status_t setStatusTracker(sp<StatusTracker> statusTracker); 416 417 /** 418 * Disconnect stream from its non-HAL endpoint. After this, 419 * start/finishConfiguration must be called before the stream can be used 420 * again. This cannot be called if the stream has outstanding dequeued 421 * buffers. 422 */ 423 status_t disconnect(); 424 425 /** 426 * Debug dump of the stream's state. 427 */ 428 virtual void dump(int fd, const Vector<String16> &args) const; 429 430 /** 431 * Add a camera3 buffer listener. Adding the same listener twice has 432 * no effect. 433 */ 434 void addBufferListener( 435 wp<Camera3StreamBufferListener> listener); 436 437 /** 438 * Remove a camera3 buffer listener. Removing the same listener twice 439 * or the listener that was never added has no effect. 440 */ 441 void removeBufferListener( 442 const sp<Camera3StreamBufferListener>& listener); 443 444 445 // Setting listener will remove previous listener (if exists) 446 virtual void setBufferFreedListener( 447 wp<Camera3StreamBufferFreedListener> listener) override; 448 449 /** 450 * Return if the buffer queue of the stream is abandoned. 451 */ 452 bool isAbandoned() const; 453 454 /** 455 * Switch a configured stream with possibly outstanding buffers in idle 456 * state. Configuration for such streams will be skipped assuming there 457 * are no changes to the stream parameters. 458 */ 459 status_t forceToIdle(); 460 461 /** 462 * Restore a forced idle stream to configured state, marking it active 463 * in case it contains outstanding buffers. 464 */ 465 status_t restoreConfiguredState(); 466 467 /** 468 * Notify buffer stream listeners about incoming request with particular frame number. 469 */ 470 void fireBufferRequestForFrameNumber(uint64_t frameNumber, 471 const CameraMetadata& settings) override; 472 473 protected: 474 const int mId; 475 /** 476 * Stream set id, used to indicate which group of this stream belongs to for buffer sharing 477 * across multiple streams. 478 * 479 * The default value is set to CAMERA3_STREAM_SET_ID_INVALID, which indicates that this stream 480 * doesn't intend to share buffers with any other streams, and this stream will fall back to 481 * the existing BufferQueue mechanism to manage the buffer allocations and buffer circulation. 482 * When a valid stream set id is set, this stream intends to use the Camera3BufferManager to 483 * manage the buffer allocations; the BufferQueue will only handle the buffer transaction 484 * between the producer and consumer. For this case, upon successfully registration, the streams 485 * with the same stream set id will potentially share the buffers allocated by 486 * Camera3BufferManager. 487 */ 488 const int mSetId; 489 490 const String8 mName; 491 // Zero for formats with fixed buffer size for given dimensions. 492 const size_t mMaxSize; 493 494 enum StreamState { 495 STATE_ERROR, 496 STATE_CONSTRUCTED, 497 STATE_IN_CONFIG, 498 STATE_IN_RECONFIG, 499 STATE_CONFIGURED, 500 STATE_PREPARING, 501 STATE_ABANDONED, 502 STATE_IN_IDLE 503 } mState; 504 505 mutable Mutex mLock; 506 507 Camera3Stream(int id, camera_stream_type type, 508 uint32_t width, uint32_t height, size_t maxSize, int format, 509 android_dataspace dataSpace, camera_stream_rotation_t rotation, 510 const String8& physicalCameraId, 511 const std::unordered_set<int32_t> &sensorPixelModesUsed, 512 int setId, bool isMultiResolution, int64_t dynamicRangeProfile, 513 int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase, 514 int32_t colorSpace); 515 516 wp<Camera3StreamBufferFreedListener> mBufferFreedListener; 517 518 /** 519 * Interface to be implemented by derived classes 520 */ 521 522 // getBuffer / returnBuffer implementations 523 524 // Since camera_stream_buffer includes a raw pointer to the stream, 525 // cast to camera_stream*, implementations must increment the 526 // refcount of the stream manually in getBufferLocked, and decrement it in 527 // returnBufferLocked. 528 virtual status_t getBufferLocked(camera_stream_buffer *buffer, 529 const std::vector<size_t>& surface_ids = std::vector<size_t>()); 530 virtual status_t returnBufferLocked(const camera_stream_buffer &buffer, 531 nsecs_t timestamp, nsecs_t readoutTimestamp, int32_t transform, 532 const std::vector<size_t>& surface_ids = std::vector<size_t>()); 533 534 virtual status_t getBuffersLocked(std::vector<OutstandingBuffer>*); 535 536 virtual status_t getInputBufferLocked(camera_stream_buffer *buffer, Size* size); 537 538 virtual status_t returnInputBufferLocked( 539 const camera_stream_buffer &buffer); 540 virtual bool hasOutstandingBuffersLocked() const = 0; 541 // Get the buffer producer of the input buffer queue. Only apply to input streams. 542 virtual status_t getInputBufferProducerLocked(sp<IGraphicBufferProducer> *producer); 543 544 // Can return -ENOTCONN when we are already disconnected (not an error) 545 virtual status_t disconnectLocked() = 0; 546 547 // Configure the buffer queue interface to the other end of the stream, 548 // after the HAL has provided usage and max_buffers values. After this call, 549 // the stream must be ready to produce all buffers for registration with 550 // HAL. 551 // Returns NO_INIT or DEAD_OBJECT if the queue has been abandoned. 552 virtual status_t configureQueueLocked() = 0; 553 554 // Get the total number of buffers in the queue 555 virtual size_t getBufferCountLocked() = 0; 556 557 // Get handout output buffer count. 558 virtual size_t getHandoutOutputBufferCountLocked() const = 0; 559 560 // Get handout input buffer count. 561 virtual size_t getHandoutInputBufferCountLocked() = 0; 562 563 // Get cached output buffer count. 564 virtual size_t getCachedOutputBufferCountLocked() const = 0; 565 virtual size_t getMaxCachedOutputBuffersLocked() const = 0; 566 567 // Get the usage flags for the other endpoint, or return 568 // INVALID_OPERATION if they cannot be obtained. 569 virtual status_t getEndpointUsage(uint64_t *usage) const = 0; 570 571 // Return whether the buffer is in the list of outstanding buffers. 572 bool isOutstandingBuffer(const camera_stream_buffer& buffer) const; 573 574 // Tracking for idle state 575 wp<StatusTracker> mStatusTracker; 576 // Status tracker component ID 577 int mStatusId; 578 579 // Tracking for stream prepare - whether this stream can still have 580 // prepareNextBuffer called on it. 581 bool mStreamUnpreparable; 582 583 uint64_t mUsage; 584 585 Condition mOutputBufferReturnedSignal; 586 587 private: 588 // Previously configured stream properties (post HAL override) 589 uint64_t mOldUsage; 590 uint32_t mOldMaxBuffers; 591 int mOldFormat; 592 android_dataspace mOldDataSpace; 593 594 Condition mInputBufferReturnedSignal; 595 static const nsecs_t kWaitForBufferDuration = 3000000000LL; // 3000 ms 596 597 void fireBufferListenersLocked(const camera_stream_buffer& buffer, 598 bool acquired, bool output, nsecs_t timestamp = 0, uint64_t frameNumber = 0); 599 List<wp<Camera3StreamBufferListener> > mBufferListenerList; 600 601 status_t cancelPrepareLocked(); 602 603 // Remove the buffer from the list of outstanding buffers. 604 void removeOutstandingBuffer(const camera_stream_buffer& buffer); 605 606 // Tracking for PREPARING state 607 608 // State of buffer preallocation. Only true if either prepareNextBuffer 609 // has been called sufficient number of times, or stream configuration 610 // had to register buffers with the HAL 611 bool mPrepared; 612 bool mPrepareBlockRequest; 613 614 Vector<camera_stream_buffer_t> mPreparedBuffers; 615 size_t mPreparedBufferIdx; 616 617 // Number of buffers allocated on last prepare call. 618 size_t mLastMaxCount; 619 620 mutable Mutex mOutstandingBuffersLock; 621 // Outstanding buffers dequeued from the stream's buffer queue. 622 List<buffer_handle_t> mOutstandingBuffers; 623 624 // Latency histogram of the wait time for handout buffer count to drop below 625 // max_buffers. 626 static const int32_t kBufferLimitLatencyBinSize = 33; //in ms 627 CameraLatencyHistogram mBufferLimitLatency; 628 629 //Keep track of original format when the stream is created in case it gets overridden 630 bool mFormatOverridden; 631 const int mOriginalFormat; 632 633 //Keep track of original dataSpace in case it gets overridden 634 bool mDataSpaceOverridden; 635 const android_dataspace mOriginalDataSpace; 636 637 String8 mPhysicalCameraId; 638 nsecs_t mLastTimestamp; 639 640 bool mIsMultiResolution = false; 641 bool mSupportOfflineProcessing = false; 642 643 bool mDeviceTimeBaseIsRealtime; 644 int mTimestampBase; 645 }; // class Camera3Stream 646 647 }; // namespace camera3 648 649 }; // namespace android 650 651 #endif 652