Утечка памяти при использовании Binder и AHandlerReflector на Android 6.0

Я написал пример кода, используя binder и AHandlerReflector, и у него есть утечки памяти после выполнения.

Весь процесс заключается в том, что существуют IMYClient и IMYService, клиент связывается со службой через связующее, а также служба связывается с клиентом через другое связующее.

В IMYService.cpp он связывается со стороной службы через связыватель (REQUEST_RESOURCES_ASYNC), а со стороны службы он вызывает функцию handleRequestDone(), определенную в IMYClient.cpp.

В IMYClient.cpp он связывается со стороной клиента через связыватель (HANDLE_REQUEST_DONE), а на стороне клиента он вызывает функцию handleRequestDone(), определенную в MYClient.cpp.

В MYClient.cpp он отправляет сообщение "handleRequestDone" в AHandlerReflector onMessageReceived(), в onMessageReceived () он вызывает callback handleRequestDone(), определенный в Test.cpp.

После выполнения Test.cpp будет пропущен поток "MYClient", определенный в MYClient.cpp, потому что деструктор ~MYClient() не вызывается. Но почему деструктор не называется?

test.cpp

#include <MYClientListener.h>
#include <MYRequest.h>
#include <MYResponse.h>
#include <utils/RefBase.h>

struct TestMYClientListener : public MYClientListener {
    TestMYClientListener();

    virtual void handleRequestDone(const sp<MYResponse> &response);
    sp<ValueUpdateListener<bool> > mRequestDone;
    sp<MYResponse> mResponse;
};

TestMYClientListener::TestMYClientListener()
:mRequestDone(new ValueUpdateListener<bool>(false))
{
}

void TestMYClientListener::handleRequestDone(const sp<MYResponse> &response)
{
    mResponse = response;
    mRequestDone->set(true);
}

static const uint64_t kWaitIntervalUs = 10000000UL;

using namespace android;

void testFunc() {
    sp<MYClient> mMYClient;
    sp<TestMYClientListener> mMYListener;

    mMYListener = new TestMYClientListener();
    mMYClient = new MYClient(mMYListener);

    mMYListener->mRequestDone->set(false);

    sp<MYRequest> req = new MYRequest();
    req->addComponent(kComponentVideoDecoder);

    mMYClient->requestResourcesAsync(req);

    mMYListener->mRequestDone->waitForValue(true, kWaitIntervalUs);
}

IMYService.h

#include <sys/types.h>  // pid_t
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <MYTypes.h>

class ALooper;
class AMessage;
class IMYClient;
class MYRequest;

class IMYService : public IInterface {
public:
    DECLARE_META_INTERFACE(MYService);

    virtual void requestResourcesAsync(const sp<IMYClient> &client,
                                       const sp<MYRequest> &request,
                                       pid_t pid) = 0;

    // Name under which this service is exported.
    static const String16 kServiceName;
};

class BpMYService : public BpInterface<IMYService> {
public:
    BpMYService(const sp<IBinder> &impl);

    virtual void requestResourcesAsync(const sp<IMYClient> &client,
                                       const sp<MYRequest> &request,
                                       pid_t pid);
};

class BnMYService : public BnInterface<IMYService> {
public:
    virtual status_t onTransact(uint32_t code,
                                const Parcel &data,
                                Parcel *reply,
                                uint32_t flags = 0);
};

IMYService.cpp

#include <utils/Log.h>
#include <IMYService.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <IMYClient.h>
#include <MYRequest.h>
#include <MYResponse.h>

enum {
    REQUEST_RESOURCES_ASYNC = IBinder::FIRST_CALL_TRANSACTION,
};

const String16 IMYService::kServiceName("media.hw_mymanager");

BpMYService::BpMYService(const sp<IBinder> &impl)
    : BpInterface<IMYService>(impl) {
}

void BpMYService::requestResourcesAsync(const sp<IMYClient> &client,
                                        const sp<MYRequest> &request,
                                        pid_t pid) {
    Parcel data;
    Parcel reply;
    data.writeInterfaceToken(IMYService::getInterfaceDescriptor());
    data.writeStrongBinder(client->asBinder(client));
    request->writeToParcel(&data);
    data.writeInt32(pid);
    remote()->transact(REQUEST_RESOURCES_ASYNC, data, &reply, IBinder::FLAG_ONEWAY);
}

IMPLEMENT_META_INTERFACE(MYService, "android.myservice");

// -------------------------------------------------------------------
status_t BnMYService::onTransact(uint32_t code,
                                 const Parcel &data,
                                 Parcel *reply,
                                 uint32_t flags) {
    ALOGV("BnMYService::onTransact");
    switch(code) {
        case REQUEST_RESOURCES_ASYNC: {
            CHECK_INTERFACE(IMYService, data, reply);
            sp<IMYClient> client = interface_cast<IMYClient>(
                    data.readStrongBinder());
            sp<MYRequest> request = new MYRequest();
            request->readFromParcel(data);
            pid_t pid = static_cast<pid_t>(data.readInt32());

            sp<MYResponse> response = NULL;
            client->handleRequestDone(response);

            break;
        }
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
    ALOGV("BnMYService::onTransact done");
    return OK;
}

IMYClient.h

#include <binder/IInterface.h>
#include <binder/Parcel.h>

class AMessage;
class MYResponse;

class IMYClient : public IInterface {
public:
    DECLARE_META_INTERFACE(MYClient);

    virtual void handleRequestDone(const sp<MYResponse> &resp) = 0;

};

class BpMYClient : public BpInterface<IMYClient> {
public:
    explicit BpMYClient(const sp<IBinder> &impl);

    virtual void handleRequestDone(const sp<MYResponse> &resp);
};

class BnMYClient : public BnInterface<IMYClient> {
public:
    virtual status_t onTransact(uint32_t code,
                                const Parcel &data,
                                Parcel *reply,
                                uint32_t flags = 0);
};

IMYClient.cpp

#include <utils/Log.h>
#include <IMYClient.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <MYResponse.h>

enum {
    HANDLE_REQUEST_DONE = IBinder::FIRST_CALL_TRANSACTION
};

BpMYClient::BpMYClient(const sp<IBinder> &impl)
    : BpInterface<IMYClient>(impl) {
}

void BpMYClient::handleRequestDone(const sp<MYResponse> &resp) {
    Parcel data;
    Parcel reply;
    data.writeInterfaceToken(IMYClient::getInterfaceDescriptor());
    if (resp != NULL) {
        resp->writeToParcel(&data);
    }
    remote()->transact(HANDLE_REQUEST_DONE, data, &reply);
}

IMPLEMENT_META_INTERFACE(MYClient, "android.myclient");

// -------------------------------------------------------------------

status_t BnMYClient::onTransact(uint32_t code,
                            const Parcel &data,
                            Parcel *reply,
                            uint32_t flags) {
    CHECK_INTERFACE(IMYClient, data, reply);
    switch(code) {
        case HANDLE_REQUEST_DONE: {
            ALOGV("HANDLE_REQUEST_DONE");
            if (data.dataSize() > 0) {
                sp<MYResponse> resp = new MYResponse();
                resp->readFromParcel(data);
                handleRequestDone(resp);
            } else {
                handleRequestDone(NULL);
            }
            break;
        }
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
    return OK;
}

MYClient.h

#include <media/stagefright/foundation/AHandlerReflector.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <utils/ValueUpdateListener_inl.h>
#include <IMYClient.h>
#include <MYClientListener.h>
#include <MYTypes.h>

class ALooper;
class AMessage;
class IMYService;
class MYClientListener;
class MYRequest;
class MYResponse;

class MYClient : public BnMYClient,
                 public IBinder::DeathRecipient {
public:
    enum {
        kWhatCmdResourceRequest = 'creq',
    };

    explicit MYClient(const sp<MYClientListener> &listener);

    virtual void binderDied(const wp<android::IBinder> &binder);

    virtual void handleRequestDone(const sp<MYResponse> &resp);

    void onMessageReceived(const sp<AMessage> &msg);

    void requestResourcesAsync(const sp<MYRequest> &request);

    bool refreshMY_l();

    sp<IMYService> getMY();

protected:
    virtual ~MYClient();  // only RefBase can call destructor

    sp<IMYService> mMYService;  // can be overriden in test

private:

    Mutex mMYServiceLock;

    sp<ALooper> mLooper;
    sp<AHandlerReflector<MYClient> > mReflector;
    sp<MYClientListener> mListener;
};

MYClient.cpp

#include <utils/Log.h>
#include <MYClient.h>
#include <unistd.h>  // getpid()
#include <binder/IServiceManager.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <IMYService.h>
#include <MYClientListener.h>
#include <MYRequest.h>
#include <MYResponse.h>
#include <cutils/properties.h>

static const int64_t kOneSecInUs = 1000000LL;

static AString parseEnum(int32_t msg) {
    return AStringPrintf("%c%c%c%c",
                        (msg >> 24) & 0xff, (msg >> 16) & 0xff, (msg >> 8) & 0xff, msg & 0xff);
}

MYClient::MYClient(const sp<MYClientListener> &listener)
    : mLooper(new ALooper()),
      mListener(listener) {

    mListener->setClient(this);
    mLooper->setName("MYClient");

    // Virtually converts this class into AHandler.
    mReflector = new AHandlerReflector<MYClient>(this);

    mLooper->registerHandler(mReflector);
    CHECK_EQ(static_cast<status_t>(OK), mLooper->start(
            false,  /* runOnCallingThread */
            true,   /* canCallJava */
            PRIORITY_NORMAL));
}

MYClient::~MYClient() {
    mLooper->unregisterHandler(mReflector->id());
    mReflector.clear();
    mLooper->stop();
    mLooper.clear();
}

void MYClient::binderDied(const wp<android::IBinder> &binder) {
}

void MYClient::handleRequestDone(const sp<MYResponse> &resp) {
    sp <AMessage> msg = new AMessage(MYClientListener::kWhatRequestDone,
                                     mReflector);
    msg->setObject("response", resp);
    msg->post();
}


void MYClient::onMessageReceived(const sp<AMessage> &msg) {
    switch(msg->what()) {
        case kWhatCmdResourceRequest: {
            sp<IMYService> my = getMY();
            if (my == NULL) {
                sp<MYResponse> response = NULL;
                mListener->handleRequestDone(response);
                return;
            }

            sp<RefBase> obj;
            CHECK(msg->findObject("request", &obj));
            sp<MYRequest> request = static_cast<MYRequest *>(obj.get());

            my->requestResourcesAsync(this, request, getpid());

            break;
        }
        case MYClientListener::kWhatRequestDone: {
            sp<RefBase> obj;
            CHECK(msg->findObject("response", &obj));

            sp<MYResponse> response = static_cast<MYResponse *>(obj.get());
            mListener->handleRequestDone(response);
            break;
        }
        default: {
            break;
        }
    }
}

void MYClient::requestResourcesAsync(const sp<MYRequest> &request) {
    sp<AMessage> msg = new AMessage(kWhatCmdResourceRequest, mReflector);
    msg->setObject("request", request);
    msg->post();
}

bool MYClient::refreshMY_l() {
    sp<IServiceManager> sm = defaultServiceManager();
    if (sm == NULL) {
        ALOGE("refreshMY_l:Failed to get default service manager.");
        return false;
    }
    sp<IBinder> binder = sm->getService(IMYService::kServiceName);
    if (binder == NULL) {
        ALOGE("refreshMY_l:Failed to get %s service.",
                String8(IMYService::kServiceName).string());
        return false;
    }
    mMYService = interface_cast<IMYService>(binder);
    return true;
}

sp<IMYService> MYClient::getMY() {
    AutoMutex l(mMYServiceLock);
    if (mMYService == NULL) {
        if (!refreshMY_l()) {
            return NULL;
        }
    }
    return mMYService;
}

MYClientListener.h

#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <utils/RefBase.h>
#include <MYTypes.h>

class AMessage;
class MYClient;
class MYRequest;
class MYResponse;

class MYClientListener : public RefBase {
public:
    enum {
        kWhatRequestDone = 'ldon',  // TODO: use a common starting indexes
    };

    MYClientListener();

    void setClient(const wp<MYClient> &client);

    ALooper::handler_id getHandlerId();

    void onMessageReceived(const sp<AMessage> &msg);

    virtual void handleRequestDone(const sp<MYResponse> &response) = 0;

    wp<MYClient> mClient;
    sp<ALooper> mLooper;
    sp<AHandlerReflector<MYClientListener> > mReflector;

protected:
    virtual ~MYClientListener();  // only RefBase can call destructor
};

MYClientListener.cpp

#include <utils/Log.h>
#include <MYClientListener.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <utils/RefBase.h>
#include <MYClient.h>
#include <MYResponse.h>

MYClientListener::MYClientListener()
    : mLooper(new ALooper()) {
    mLooper->setName("MYClientListener");

    // Virtually converts this class into AHandler.
    mReflector = new AHandlerReflector<MYClientListener>(this);
    mLooper->registerHandler(mReflector);
    CHECK_EQ(static_cast<status_t>(OK), mLooper->start(
            false,  /* runOnCallingThread */
            true,   /* canCallJava */
            PRIORITY_NORMAL));
}

MYClientListener::~MYClientListener() {
    ALOGV("~MYClientListener");
    mLooper->stop();
    mLooper->unregisterHandler(mReflector->id());
}

void MYClientListener::onMessageReceived(const sp<AMessage> &msg) {
               ALOGE("Error: msg %d not handled:", msg->what());
}

ALooper::handler_id MYClientListener::getHandlerId() {
    return mReflector->id();
}

void MYClientListener::setClient(const wp<MYClient> &client) {
    CHECK(mClient == NULL);
    mClient = client;
}

0 ответов

Другие вопросы по тегам