Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6f70828 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce SurfaceFlinger Queued Transaction"

parents 2da79a60 dca14285
Loading
Loading
Loading
Loading
+172 −169
Original line number Diff line number Diff line
@@ -1914,19 +1914,17 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT

bool SurfaceFlinger::handleMessageTransaction() {
    ATRACE_CALL();
    uint32_t transactionFlags = peekTransactionFlags();

    bool flushedATransaction = flushTransactionQueues();

    if (getTransactionFlags(eTransactionFlushNeeded)) {
        flushPendingTransactionQueues();
        flushTransactionQueue();
    }
    uint32_t transactionFlags = peekTransactionFlags();
    bool runHandleTransaction =
            (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) ||
            flushedATransaction ||
            mForceTraversal;
            ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal;

    if (runHandleTransaction) {
        handleTransaction(eTransactionMask);
    } else {
        getTransactionFlags(eTransactionFlushNeeded);
    }

    if (transactionFlushNeeded()) {
@@ -2828,7 +2826,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) {
        });
    }

    commitInputWindowCommands();
    commitTransaction();
}

@@ -2869,11 +2866,6 @@ void SurfaceFlinger::updateInputWindowInfo() {
                                                                     : nullptr);
}

void SurfaceFlinger::commitInputWindowCommands() {
    mInputWindowCommands.merge(mPendingInputWindowCommands);
    mPendingInputWindowCommands.clear();
}

void SurfaceFlinger::updateCursorAsync() {
    compositionengine::CompositionRefreshArgs refreshArgs;
    for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
@@ -3237,55 +3229,55 @@ void SurfaceFlinger::setTraversalNeeded() {
    mForceTraversal = true;
}

bool SurfaceFlinger::flushTransactionQueues() {
void SurfaceFlinger::flushPendingTransactionQueues() {
    // to prevent onHandleDestroyed from being called while the lock is held,
    // we must keep a copy of the transactions (specifically the composer
    // states) around outside the scope of the lock
    std::vector<const TransactionState> transactions;
    bool flushedATransaction = false;
    {
        Mutex::Autolock _l(mStateLock);
        Mutex::Autolock _l(mQueueLock);

        auto it = mTransactionQueues.begin();
        while (it != mTransactionQueues.end()) {
        auto it = mPendingTransactionQueues.begin();
        while (it != mPendingTransactionQueues.end()) {
            auto& [applyToken, transactionQueue] = *it;

            while (!transactionQueue.empty()) {
                const auto& transaction = transactionQueue.front();
                if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
                                                   transaction.states)) {
                    setTransactionFlags(eTransactionFlushNeeded);
                    break;
                }
                transactions.push_back(transaction);
                applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
                                      transaction.displays, transaction.flags,
                                      mPendingInputWindowCommands, transaction.desiredPresentTime,
                                      transaction.isAutoTimestamp, transaction.buffer,
                                      transaction.postTime, transaction.privileged,
                                      transaction.hasListenerCallbacks,
                                      transaction.listenerCallbacks, transaction.originPid,
                                      transaction.originUid, transaction.id, /*isMainThread*/ true);
                transactionQueue.pop();
                flushedATransaction = true;
            }

            if (transactionQueue.empty()) {
                it = mTransactionQueues.erase(it);
                mTransactionCV.broadcast();
                it = mPendingTransactionQueues.erase(it);
                mTransactionQueueCV.broadcast();
            } else {
                it = std::next(it, 1);
            }
        }
    }
    return flushedATransaction;

    {
        Mutex::Autolock _l(mStateLock);
        for (const auto& transaction : transactions) {
            applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
                                  transaction.displays, transaction.flags, mInputWindowCommands,
                                  transaction.desiredPresentTime, transaction.isAutoTimestamp,
                                  transaction.buffer, transaction.postTime, transaction.privileged,
                                  transaction.hasListenerCallbacks, transaction.listenerCallbacks,
                                  transaction.originPid, transaction.originUid, transaction.id);
        }
    }
}

bool SurfaceFlinger::transactionFlushNeeded() {
    return !mTransactionQueues.empty();
    Mutex::Autolock _l(mQueueLock);
    return !mPendingTransactionQueues.empty();
}


bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                                   const Vector<ComposerState>& states,
                                                   bool updateTransactionCounters) {
@@ -3307,6 +3299,8 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
        if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
          ready = false;
        }

        Mutex::Autolock _l(mStateLock);
        sp<Layer> layer = nullptr;
        if (s.surface) {
            layer = fromHandleLocked(s.surface).promote();
@@ -3321,7 +3315,6 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
        if (updateTransactionCounters) {
            // See BufferStateLayer::mPendingBufferTransactions
            if (layer) layer->incrementPendingBufferCount();

        }
    }
    return ready;
@@ -3338,27 +3331,28 @@ status_t SurfaceFlinger::setTransactionState(
    const int64_t postTime = systemTime();

    bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();

    Mutex::Autolock _l(mStateLock);
    {
        Mutex::Autolock _l(mQueueLock);

        // If its TransactionQueue already has a pending TransactionState or if it is pending
    auto itr = mTransactionQueues.find(applyToken);
        auto itr = mPendingTransactionQueues.find(applyToken);
        // if this is an animation frame, wait until prior animation frame has
        // been applied by SF
        if (flags & eAnimation) {
        while (itr != mTransactionQueues.end()) {
            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
            while (itr != mPendingTransactionQueues.end() ||
                   (!mTransactionQueue.empty() && mAnimTransactionPending)) {
                status_t err = mTransactionQueueCV.waitRelative(mQueueLock, s2ns(5));
                if (CC_UNLIKELY(err != NO_ERROR)) {
                    ALOGW_IF(err == TIMED_OUT,
                             "setTransactionState timed out "
                             "waiting for animation frame to apply");
                    break;
                }
            itr = mTransactionQueues.find(applyToken);
                itr = mPendingTransactionQueues.find(applyToken);
            }
        }

    const bool pendingTransactions = itr != mTransactionQueues.end();
        const bool pendingTransactions = itr != mPendingTransactionQueues.end();
        // Expected present time is computed and cached on invalidate, so it may be stale.
        if (!pendingTransactions) {
            const auto now = systemTime();
@@ -3373,55 +3367,117 @@ status_t SurfaceFlinger::setTransactionState(
            }
        }

        // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
        if (flags & eEarlyWakeup) {
            ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
        }

        if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
            ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
            flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
        }

        IPCThreadState* ipc = IPCThreadState::self();
        const int originPid = ipc->getCallingPid();
        const int originUid = ipc->getCallingUid();

        // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount
        // if the transaction contains a buffer.
    if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states, true) ||
        if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states,
                                           true) ||
            pendingTransactions) {
        mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags,
                                               desiredPresentTime, isAutoTimestamp, uncacheBuffer,
                                               postTime, privileged, hasListenerCallbacks,
                                               listenerCallbacks, originPid, originUid,
                                               transactionId);
            mPendingTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays,
                                                          flags, inputWindowCommands,
                                                          desiredPresentTime, isAutoTimestamp,
                                                          uncacheBuffer, postTime, privileged,
                                                          hasListenerCallbacks, listenerCallbacks,
                                                          originPid, originUid, transactionId);

            setTransactionFlags(eTransactionFlushNeeded);
            return NO_ERROR;
        }

    applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands,
                          desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged,
                          hasListenerCallbacks, listenerCallbacks, originPid, originUid,
                          transactionId, /*isMainThread*/ false);
        mTransactionQueue.emplace_back(frameTimelineVsyncId, states, displays, flags,
                                       inputWindowCommands, desiredPresentTime, isAutoTimestamp,
                                       uncacheBuffer, postTime, privileged, hasListenerCallbacks,
                                       listenerCallbacks, originPid, originUid, transactionId);
    }

    const auto schedule = [](uint32_t flags) {
        if (flags & eEarlyWakeup) return TransactionSchedule::Early;
        if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
        if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
        return TransactionSchedule::Late;
    }(flags);
    setTransactionFlags(eTransactionFlushNeeded, schedule);

    // if this is a synchronous transaction, wait for it to take effect
    // before returning.
    const bool synchronous = flags & eSynchronous;
    const bool syncInput = inputWindowCommands.syncInputWindows;
    if (!synchronous && !syncInput) {
        return NO_ERROR;
    }

void SurfaceFlinger::applyTransactionState(
        int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
        const Vector<DisplayState>& displays, uint32_t flags,
        const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
        bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime,
        bool privileged, bool hasListenerCallbacks,
        const std::vector<ListenerCallbacks>& listenerCallbacks, int originPid, int originUid,
        uint64_t transactionId, bool isMainThread) {
    uint32_t transactionFlags = 0;
    // Handle synchronous cases.
    {
        Mutex::Autolock _l(mStateLock);
        if (synchronous) {
            mTransactionPending = true;
        }
        if (syncInput) {
            mPendingSyncInputWindows = true;
        }

    if (flags & eAnimation) {
        // For window updates that are part of an animation we must wait for
        // previous animation "frames" to be handled.
        while (!isMainThread && mAnimTransactionPending) {
        // applyTransactionState can be called by either the main SF thread or by
        // another process through setTransactionState.  While a given process may wish
        // to wait on synchronous transactions, the main SF thread should never
        // be blocked.  Therefore, we only wait if isMainThread is false.
        while (mTransactionPending || mPendingSyncInputWindows) {
            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
            if (CC_UNLIKELY(err != NO_ERROR)) {
                // just in case something goes wrong in SF, return to the
                // caller after a few seconds.
                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
                        "waiting for previous animation frame");
                mAnimTransactionPending = false;
                // called after a few seconds.
                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
                mTransactionPending = false;
                mPendingSyncInputWindows = false;
                break;
            }
        }
    }
    return NO_ERROR;
}

void SurfaceFlinger::flushTransactionQueue() {
    std::vector<TransactionState> transactionQueue;
    {
        Mutex::Autolock _l(mQueueLock);
        if (!mTransactionQueue.empty()) {
            transactionQueue.swap(mTransactionQueue);
        }
        mTransactionQueueCV.broadcast();
    }

    Mutex::Autolock _l(mStateLock);
    for (const auto& t : transactionQueue) {
        applyTransactionState(t.frameTimelineVsyncId, t.states, t.displays, t.flags,
                              t.inputWindowCommands, t.desiredPresentTime, t.isAutoTimestamp,
                              t.buffer, t.postTime, t.privileged, t.hasListenerCallbacks,
                              t.listenerCallbacks, t.originPid, t.originUid, t.id);
    }
}

void SurfaceFlinger::applyTransactionState(int64_t frameTimelineVsyncId,
                                           const Vector<ComposerState>& states,
                                           const Vector<DisplayState>& displays, uint32_t flags,
                                           const InputWindowCommands& inputWindowCommands,
                                           const int64_t desiredPresentTime, bool isAutoTimestamp,
                                           const client_cache_t& uncacheBuffer,
                                           const int64_t postTime, bool privileged,
                                           bool hasListenerCallbacks,
                                           const std::vector<ListenerCallbacks>& listenerCallbacks,
                                           int originPid, int originUid, uint64_t transactionId) {
    uint32_t transactionFlags = 0;

    for (const DisplayState& display : displays) {
        transactionFlags |= setDisplayStateLocked(display);
@@ -3480,80 +3536,25 @@ void SurfaceFlinger::applyTransactionState(
        transactionFlags = eTransactionNeeded;
    }

    // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit
    // so we don't have to wake up again next frame to preform an uneeded traversal.
    if (isMainThread && (transactionFlags & eTraversalNeeded)) {
        transactionFlags = transactionFlags & (~eTraversalNeeded);
        mForceTraversal = true;
    }

    const auto schedule = [](uint32_t flags) {
        if (flags & eEarlyWakeup) return TransactionSchedule::Early;
        if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
        if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
        return TransactionSchedule::Late;
    }(flags);

    if (transactionFlags) {
        if (mInterceptor->isEnabled()) {
            mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
                                          originPid, originUid, transactionId);
        }

        // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
        if (flags & eEarlyWakeup) {
            ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
        // We are on the main thread, we are about to preform a traversal. Clear the traversal bit
        // so we don't have to wake up again next frame to preform an unnecessary traversal.
        if (transactionFlags & eTraversalNeeded) {
            transactionFlags = transactionFlags & (~eTraversalNeeded);
            mForceTraversal = true;
        }

        if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
            ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
            flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
        if (transactionFlags) {
            setTransactionFlags(transactionFlags);
        }

        // this triggers the transaction
        setTransactionFlags(transactionFlags, schedule);

        if (flags & eAnimation) {
            mAnimTransactionPending = true;
        }

        // if this is a synchronous transaction, wait for it to take effect
        // before returning.
        const bool synchronous = flags & eSynchronous;
        const bool syncInput = inputWindowCommands.syncInputWindows;
        if (!synchronous && !syncInput) {
            return;
        }

        if (synchronous) {
            mTransactionPending = true;
        }
        if (syncInput) {
            mPendingSyncInputWindows = true;
        }


        // applyTransactionState can be called by either the main SF thread or by
        // another process through setTransactionState.  While a given process may wish
        // to wait on synchronous transactions, the main SF thread should never
        // be blocked.  Therefore, we only wait if isMainThread is false.
        while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) {
            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
            if (CC_UNLIKELY(err != NO_ERROR)) {
                // just in case something goes wrong in SF, return to the
                // called after a few seconds.
                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
                mTransactionPending = false;
                mPendingSyncInputWindows = false;
                break;
            }
        }
    } else {
        // Update VsyncModulator state machine even if transaction is not needed.
        if (schedule == TransactionSchedule::EarlyStart ||
            schedule == TransactionSchedule::EarlyEnd) {
            modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
        }
    }
}

@@ -3945,7 +3946,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(
}

uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
    bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
    bool hasChanges = mInputWindowCommands.merge(inputWindowCommands);
    return hasChanges ? eTraversalNeeded : 0;
}

@@ -4210,9 +4211,11 @@ void SurfaceFlinger::onInitializeDisplays() {
    d.width = 0;
    d.height = 0;
    displays.add(d);
    setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr,
                        mPendingInputWindowCommands, systemTime(), true, {}, false, {},
                        0 /* Undefined transactionId */);

    // This called on the main thread, apply it directly.
    applyTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0,
                          mInputWindowCommands, systemTime(), true, {}, systemTime(), true, false,
                          {}, getpid(), getuid(), 0 /* Undefined transactionId */);

    setPowerModeInternal(display, hal::PowerMode::ON);
    const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
@@ -5389,7 +5392,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r

void SurfaceFlinger::repaintEverything() {
    mRepaintEverything = true;
    signalTransaction();
    setTransactionFlags(eTransactionNeeded);
}

void SurfaceFlinger::repaintEverythingForHWC() {
+16 −9
Original line number Diff line number Diff line
@@ -434,15 +434,16 @@ private:
    struct TransactionState {
        TransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& composerStates,
                         const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
                         int64_t desiredPresentTime, bool isAutoTimestamp,
                         const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged,
                         bool hasListenerCallbacks,
                         const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
                         bool isAutoTimestamp, const client_cache_t& uncacheBuffer,
                         int64_t postTime, bool privileged, bool hasListenerCallbacks,
                         std::vector<ListenerCallbacks> listenerCallbacks, int originPid,
                         int originUid, uint64_t transactionId)
              : frameTimelineVsyncId(frameTimelineVsyncId),
                states(composerStates),
                displays(displayStates),
                flags(transactionFlags),
                inputWindowCommands(inputWindowCommands),
                desiredPresentTime(desiredPresentTime),
                isAutoTimestamp(isAutoTimestamp),
                buffer(uncacheBuffer),
@@ -458,6 +459,7 @@ private:
        Vector<ComposerState> states;
        Vector<DisplayState> displays;
        uint32_t flags;
        InputWindowCommands inputWindowCommands;
        const int64_t desiredPresentTime;
        const bool isAutoTimestamp;
        client_cache_t buffer;
@@ -723,6 +725,7 @@ private:
    /*
     * Transactions
     */
    void flushTransactionQueue();
    void applyTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
                               const Vector<DisplayState>& displays, uint32_t flags,
                               const InputWindowCommands& inputWindowCommands,
@@ -730,10 +733,12 @@ private:
                               const client_cache_t& uncacheBuffer, const int64_t postTime,
                               bool privileged, bool hasListenerCallbacks,
                               const std::vector<ListenerCallbacks>& listenerCallbacks,
                               int originPid, int originUid, uint64_t transactionId,
                               bool isMainThread = false) REQUIRES(mStateLock);
                               int originPid, int originUid, uint64_t transactionId)
            REQUIRES(mStateLock);
    // Returns true if at least one transaction was flushed
    bool flushTransactionQueues();
    // flush pending transaction that was presented after desiredPresentTime.
    void flushPendingTransactionQueues();
    // Returns true if there is at least one transaction that needs to be flushed
    bool transactionFlushNeeded();
    uint32_t getTransactionFlags(uint32_t flags);
@@ -751,7 +756,7 @@ private:
    void commitOffscreenLayers();
    bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                       const Vector<ComposerState>& states,
                                       bool updateTransactionCounters = false) REQUIRES(mStateLock);
                                       bool updateTransactionCounters = false);
    uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
    uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
            REQUIRES(mStateLock);
@@ -1168,8 +1173,11 @@ private:
    uint32_t mTexturePoolSize = 0;
    std::vector<uint32_t> mTexturePool;

    std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues;

    mutable Mutex mQueueLock;
    Condition mTransactionQueueCV;
    std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
            mPendingTransactionQueues GUARDED_BY(mQueueLock);
    std::vector<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
    /*
     * Feature prototyping
     */
@@ -1246,7 +1254,6 @@ private:
    const float mEmulatedDisplayDensity;

    sp<os::IInputFlinger> mInputFlinger;
    InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
    // Should only be accessed by the main thread.
    InputWindowCommands mInputWindowCommands;

+3 −0
Original line number Diff line number Diff line
@@ -68,6 +68,9 @@ public:
                                       Rect(displayState.layerStackSpaceRect), Rect(resolution));
                t.apply();
                SurfaceComposerClient::Transaction().apply(true);
                // wait for 3 vsyncs to ensure the buffer is latched.
                usleep(static_cast<int32_t>(1e6 / displayConfig.refreshRate) * 3);

                BufferItem item;
                itemConsumer->acquireBuffer(&item, 0, true);
                auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
+2 −2
Original line number Diff line number Diff line
@@ -365,7 +365,7 @@ public:
        return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
    }

    auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
    auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }

    auto setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
                             const Vector<DisplayState>& displays, uint32_t flags,
@@ -381,7 +381,7 @@ public:
                                             listenerCallbacks, transactionId);
    }

    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
    auto flushPendingTransactionQueues() { return mFlinger->flushPendingTransactionQueues(); };

    auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
        return mFlinger->onTransact(code, data, reply, flags);
+10 −10

File changed.

Preview size limit exceeded, changes collapsed.