xref: /aosp_15_r20/external/oboe/apps/OboeTester/app/src/main/cpp/TestErrorCallback.h (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1 /*
2  * Copyright 2022 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 OBOETESTER_TEST_ERROR_CALLBACK_H
18 #define OBOETESTER_TEST_ERROR_CALLBACK_H
19 
20 #include "oboe/Oboe.h"
21 #include <thread>
22 
23 /**
24  * This code is an experiment to see if we can cause a crash from the ErrorCallback.
25  */
26 class TestErrorCallback {
27 public:
28 
29     oboe::Result open();
30     oboe::Result start();
31     oboe::Result stop();
32     oboe::Result close();
33 
34     int test();
35 
getCallbackMagic()36     int32_t getCallbackMagic() {
37         return mCallbackMagic.load();
38     }
39 
40 protected:
41 
42     std::atomic<int32_t> mCallbackMagic{0};
43 
44 private:
45 
cleanup()46     void cleanup() {
47         mDataCallback.reset();
48         mErrorCallback.reset();
49         mStream.reset();
50     }
51 
52     class MyDataCallback : public oboe::AudioStreamDataCallback {    public:
53 
54         oboe::DataCallbackResult onAudioReady(
55                 oboe::AudioStream *audioStream,
56                 void *audioData,
57                 int32_t numFrames) override;
58 
59     };
60 
61     class MyErrorCallback : public oboe::AudioStreamErrorCallback {
62     public:
63 
MyErrorCallback(TestErrorCallback * parent)64         MyErrorCallback(TestErrorCallback *parent): mParent(parent) {}
65 
~MyErrorCallback()66         virtual ~MyErrorCallback() {
67             // If the delete occurs before onErrorAfterClose() then this bad magic
68             // value will be seen by the Java test code, causing a failure.
69             // It is also possible that this code will just cause OboeTester to crash!
70             mMagic = 0xdeadbeef;
71             LOGE("%s() called", __func__);
72         }
73 
onErrorBeforeClose(oboe::AudioStream * oboeStream,oboe::Result error)74         void onErrorBeforeClose(oboe::AudioStream *oboeStream, oboe::Result error) override {
75             LOGE("%s() - error = %s, parent = %p",
76                  __func__, oboe::convertToText(error), &mParent);
77             // Trigger a crash by "deleting" this callback object while in use!
78             // Do not try this at home. We are just trying to reproduce the crash
79             // reported in #1603.
80             std::thread t([this]() {
81                     this->mParent->cleanup(); // Possibly delete stream and callback objects.
82                     LOGE("onErrorBeforeClose called cleanup!");
83                 });
84             t.detach();
85             // There is a race condition between the deleting thread and this thread.
86             // We do not want to add synchronization because the object is getting deleted
87             // and cannot be relied on.
88             // So we sleep here to give the deleting thread a chance to win the race.
89             usleep(10 * 1000);
90         }
91 
onErrorAfterClose(oboe::AudioStream * oboeStream,oboe::Result error)92         void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override {
93             // The callback was probably deleted by now.
94             LOGE("%s() - error = %s, mMagic = 0x%08X",
95                  __func__, oboe::convertToText(error), mMagic.load());
96             mParent->mCallbackMagic = mMagic.load();
97         }
98 
99     private:
100         TestErrorCallback *mParent;
101         // This must match the value in TestErrorCallbackActivity.java
102         static constexpr int32_t kMagicGood = 0x600DCAFE;
103         std::atomic<int32_t> mMagic{kMagicGood};
104     };
105 
106     std::shared_ptr<oboe::AudioStream> mStream;
107     std::shared_ptr<MyDataCallback> mDataCallback;
108     std::shared_ptr<MyErrorCallback> mErrorCallback;
109 
110     static constexpr int kChannelCount = 2;
111 };
112 
113 #endif //OBOETESTER_TEST_ERROR_CALLBACK_H
114