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