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