Merge "Conditional start the media.transcoding service." into sc-dev
diff --git a/apex/mediatranscoding.rc b/apex/mediatranscoding.rc
index ae9f8ba..24306a2 100644
--- a/apex/mediatranscoding.rc
+++ b/apex/mediatranscoding.rc
@@ -8,5 +8,4 @@
     ioprio rt 4
     # Restrict to little cores only with system-background cpuset.
     writepid /dev/cpuset/system-background/tasks
-    interface aidl media.transcoding
     disabled
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index e2c8f8f..daa923e 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -127,7 +127,7 @@
 
     if ((as == AUDIO_SOURCE_FM_TUNER
             && !(captureAudioOutputAllowed(mIdentity) || captureTunerAudioInputAllowed(mIdentity)))
-            || !recordingAllowed(mIdentity)) {
+            || !recordingAllowed(mIdentity, (audio_source_t)as)) {
         return PERMISSION_DENIED;
     }
     Mutex::Autolock lock(mLock);
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index e3931b1..214a174 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -67,7 +67,7 @@
     return packages[0];
 }
 
-static int32_t getOpForSource(audio_source_t source) {
+int32_t getOpForSource(audio_source_t source) {
   switch (source) {
     case AUDIO_SOURCE_HOTWORD:
       return AppOpsManager::OP_RECORD_AUDIO_HOTWORD;
@@ -133,8 +133,8 @@
     return true;
 }
 
-bool recordingAllowed(const Identity& identity) {
-    return checkRecordingInternal(identity, String16(), /*start*/ false, AUDIO_SOURCE_DEFAULT);
+bool recordingAllowed(const Identity& identity, audio_source_t source) {
+    return checkRecordingInternal(identity, String16(), /*start*/ false, source);
 }
 
 bool startRecording(const Identity& identity, const String16& msg, audio_source_t source) {
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 6e75746..e7132b8 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -80,7 +80,8 @@
     }
 }
 
-bool recordingAllowed(const media::permission::Identity& identity);
+bool recordingAllowed(const media::permission::Identity& identity,
+        audio_source_t source = AUDIO_SOURCE_DEFAULT);
 bool startRecording(const media::permission::Identity& identity,
     const String16& msg, audio_source_t source);
 void finishRecording(const media::permission::Identity& identity, audio_source_t source);
@@ -98,6 +99,7 @@
 bool modifyPhoneStateAllowed(const media::permission::Identity& identity);
 bool bypassInterruptionPolicyAllowed(const media::permission::Identity& identity);
 void purgePermissionCache();
+int32_t getOpForSource(audio_source_t source);
 
 media::permission::Identity getCallingIdentity();
 
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 2436248..0af4c7b 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -148,14 +148,6 @@
     void                setFinalVolume(float volume);
     float               getFinalVolume() const { return mFinalVolume; }
 
-    /** @return true if the track has changed (metadata or volume) since
-     *          the last time this function was called,
-     *          true if this function was never called since the track creation,
-     *          false otherwise.
-     *  Thread safe.
-     */
-    bool            readAndClearHasChanged() { return !mChangeNotified.test_and_set(); }
-
     using SourceMetadatas = std::vector<playback_track_metadata_v7_t>;
     using MetadataInserter = std::back_insert_iterator<SourceMetadatas>;
     /** Copy the track metadata in the provided iterator. Thread safe. */
@@ -234,8 +226,6 @@
     bool presentationComplete(int64_t framesWritten, size_t audioHalFrames);
     void signalClientFlag(int32_t flag);
 
-    /** Set that a metadata has changed and needs to be notified to backend. Thread safe. */
-    void setMetadataHasChanged() { mChangeNotified.clear(); }
 public:
     void triggerEvents(AudioSystem::sync_event_t type);
     virtual void invalidate();
@@ -320,8 +310,6 @@
     bool                mFlushHwPending; // track requests for thread flush
     bool                mPauseHwPending = false; // direct/offload track request for thread pause
     audio_output_flags_t mFlags;
-    // If the last track change was notified to the client with readAndClearHasChanged
-    std::atomic_flag     mChangeNotified = ATOMIC_FLAG_INIT;
     TeePatches  mTeePatches;
 };  // end of Track
 
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 451c198..a1c2de7 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -19,17 +19,18 @@
     #error This header file should only be included from AudioFlinger.h
 #endif
 
-// Checks and monitors OP_RECORD_AUDIO
+// Checks and monitors app ops for audio record
 class OpRecordAudioMonitor : public RefBase {
 public:
     ~OpRecordAudioMonitor() override;
-    bool hasOpRecordAudio() const;
+    bool hasOp() const;
+    int32_t getOp() const { return mAppOp; }
 
     static sp<OpRecordAudioMonitor> createIfNeeded
         (const media::permission::Identity& identity, const audio_attributes_t& attr);
 
 private:
-    explicit OpRecordAudioMonitor(const media::permission::Identity& identity);
+    OpRecordAudioMonitor(const media::permission::Identity& identity, int32_t appOp);
     void onFirstRef() override;
 
     AppOpsManager mAppOpsManager;
@@ -44,12 +45,13 @@
     };
 
     sp<RecordAudioOpCallback> mOpCallback;
-    // called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback
-    // and in onFirstRef()
-    void checkRecordAudio();
+    // called by RecordAudioOpCallback when the app op for this OpRecordAudioMonitor is updated
+    // in AppOp callback and in onFirstRef()
+    void checkOp();
 
-    std::atomic_bool mHasOpRecordAudio;
+    std::atomic_bool mHasOp;
     const media::permission::Identity mIdentity;
+    const int32_t mAppOp;
 };
 
 // record track
@@ -149,7 +151,7 @@
 
             bool                               mSilenced;
 
-            // used to enforce OP_RECORD_AUDIO
+            // used to enforce the audio record app op corresponding to this track's audio source
             sp<OpRecordAudioMonitor>           mOpRecordAudioMonitor;
             std::string                        mSharedAudioPackageName = {};
             int32_t                            mStartFrames = -1;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d42a6ca..d878611 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1798,8 +1798,14 @@
 
 template <typename T>
 bool AudioFlinger::ThreadBase::ActiveTracks<T>::readAndClearHasChanged() {
-    const bool hasChanged = mHasChanged;
+    bool hasChanged = mHasChanged;
     mHasChanged = false;
+
+    for (const sp<T> &track : mActiveTracks) {
+        // Do not short-circuit as all hasChanged states must be reset
+        // as all the metadata are going to be sent
+        hasChanged |= track->readAndClearHasChanged();
+    }
     return hasChanged;
 }
 
@@ -1986,7 +1992,7 @@
 
 void AudioFlinger::PlaybackThread::onFirstRef()
 {
-    if (mOutput == nullptr || mOutput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         ALOGE("The stream is not open yet"); // This should not happen.
     } else {
         // setEventCallback will need a strong pointer as a parameter. Calling it
@@ -2695,7 +2701,7 @@
 
 status_t AudioFlinger::DirectOutputThread::selectPresentation(int presentationId, int programId) {
     Mutex::Autolock _l(mLock);
-    if (mOutput == nullptr || mOutput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         return NO_INIT;
     }
     return mOutput->stream->selectPresentation(presentationId, programId);
@@ -2992,16 +2998,7 @@
 
 void AudioFlinger::PlaybackThread::updateMetadata_l()
 {
-    if (mOutput == nullptr || mOutput->stream == nullptr ) {
-        return; // That should not happen
-    }
-    bool hasChanged = mActiveTracks.readAndClearHasChanged();
-    for (const sp<Track> &track : mActiveTracks) {
-        // Do not short-circuit as all hasChanged states must be reset
-        // as all the metadata are going to be sent
-        hasChanged |= track->readAndClearHasChanged();
-    }
-    if (!hasChanged) {
+    if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
         return; // nothing to do
     }
     StreamOutHalInterface::SourceMetadata metadata;
@@ -8186,7 +8183,7 @@
 {
     ALOGV("RecordThread::getActiveMicrophones");
     AutoMutex _l(mLock);
-    if (mInput == nullptr || mInput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         return NO_INIT;
     }
     status_t status = mInput->stream->getActiveMicrophones(activeMicrophones);
@@ -8198,7 +8195,7 @@
 {
     ALOGV("setPreferredMicrophoneDirection(%d)", direction);
     AutoMutex _l(mLock);
-    if (mInput == nullptr || mInput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         return NO_INIT;
     }
     return mInput->stream->setPreferredMicrophoneDirection(direction);
@@ -8208,7 +8205,7 @@
 {
     ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
     AutoMutex _l(mLock);
-    if (mInput == nullptr || mInput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         return NO_INIT;
     }
     return mInput->stream->setPreferredMicrophoneFieldDimension(zoom);
@@ -8259,9 +8256,8 @@
 
 void AudioFlinger::RecordThread::updateMetadata_l()
 {
-    if (mInput == nullptr || mInput->stream == nullptr ||
-            !mActiveTracks.readAndClearHasChanged()) {
-        return;
+    if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
+        return; // nothing to do
     }
     StreamInHalInterface::SinkMetadata metadata;
     for (const sp<RecordTrack> &track : mActiveTracks) {
@@ -9959,14 +9955,16 @@
                 }
             }
         }
+        for (const sp<MmapTrack> &track : mActiveTracks) {
+            track->setMetadataHasChanged();
+        }
     }
 }
 
 void AudioFlinger::MmapPlaybackThread::updateMetadata_l()
 {
-    if (mOutput == nullptr || mOutput->stream == nullptr ||
-            !mActiveTracks.readAndClearHasChanged()) {
-        return;
+    if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
+        return; // nothing to do
     }
     StreamOutHalInterface::SourceMetadata metadata;
     for (const sp<MmapTrack> &track : mActiveTracks) {
@@ -10093,9 +10091,8 @@
 
 void AudioFlinger::MmapCaptureThread::updateMetadata_l()
 {
-    if (mInput == nullptr || mInput->stream == nullptr ||
-            !mActiveTracks.readAndClearHasChanged()) {
-        return;
+    if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
+        return; // nothing to do
     }
     StreamInHalInterface::SinkMetadata metadata;
     for (const sp<MmapTrack> &track : mActiveTracks) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 65db986..17acb16 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -527,6 +527,8 @@
                     }
                 }
 
+    virtual     bool isStreamInitialized() = 0;
+
 protected:
 
                 // entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -741,7 +743,9 @@
                     void            updatePowerState(sp<ThreadBase> thread, bool force = false);
 
                     /** @return true if one or move active tracks was added or removed since the
-                     *          last time this function was called or the vector was created. */
+                     *          last time this function was called or the vector was created.
+                     *          true if volume of one of active tracks was changed.
+                     */
                     bool            readAndClearHasChanged();
 
                 private:
@@ -993,6 +997,10 @@
                                         && outDeviceTypes().count(mTimestampCorrectedDevice) != 0;
                             }
 
+    virtual     bool        isStreamInitialized() {
+                                return !(mOutput == nullptr || mOutput->stream == nullptr);
+                            }
+
                 audio_channel_mask_t hapticChannelMask() const override {
                                          return mHapticChannelMask;
                                      }
@@ -1780,6 +1788,10 @@
                                           audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
                                           int64_t sharedAudioStartMs = -1);
 
+    virtual bool        isStreamInitialized() {
+                            return !(mInput == nullptr || mInput->stream == nullptr);
+                        }
+
 protected:
             void        dumpInternals_l(int fd, const Vector<String16>& args) override;
             void        dumpTracks_l(int fd, const Vector<String16>& args) override;
@@ -1949,6 +1961,8 @@
     virtual     void        setRecordSilenced(audio_port_handle_t portId __unused,
                                               bool silenced __unused) {}
 
+    virtual     bool        isStreamInitialized() { return false; }
+
  protected:
                 void        dumpInternals_l(int fd, const Vector<String16>& args) override;
                 void        dumpTracks_l(int fd, const Vector<String16>& args) override;
@@ -2011,6 +2025,10 @@
 
                 status_t    getExternalPosition(uint64_t *position, int64_t *timeNanos) override;
 
+    virtual     bool        isStreamInitialized() {
+                                return !(mOutput == nullptr || mOutput->stream == nullptr);
+                            }
+
 protected:
                 void        dumpInternals_l(int fd, const Vector<String16>& args) override;
 
@@ -2043,6 +2061,10 @@
 
                 status_t       getExternalPosition(uint64_t *position, int64_t *timeNanos) override;
 
+    virtual     bool           isStreamInitialized() {
+                                   return !(mInput == nullptr || mInput->stream == nullptr);
+                               }
+
 protected:
 
                 AudioStreamIn*  mInput;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 38dab5b..92f129c 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -255,6 +255,17 @@
 
     audio_channel_mask_t channelMask() const { return mChannelMask; }
 
+    /** @return true if the track has changed (metadata or volume) since
+     *          the last time this function was called,
+     *          true if this function was never called since the track creation,
+     *          false otherwise.
+     *  Thread safe.
+     */
+    bool readAndClearHasChanged() { return !mChangeNotified.test_and_set(); }
+
+    /** Set that a metadata has changed and needs to be notified to backend. Thread safe. */
+    void setMetadataHasChanged() { mChangeNotified.clear(); }
+
 protected:
     DISALLOW_COPY_AND_ASSIGN(TrackBase);
 
@@ -391,6 +402,9 @@
     std::atomic<FrameTime> mKernelFrameTime{};     // last frame time on kernel side.
     const pid_t         mCreatorPid;  // can be different from mclient->pid() for instance
                                       // when created by NuPlayer on behalf of a client
+
+    // If the last track change was notified to the client with readAndClearHasChanged
+    std::atomic_flag    mChangeNotified = ATOMIC_FLAG_INIT;
 };
 
 // PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 3258689..8be7c86 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -2215,7 +2215,7 @@
         return nullptr;
     }
 
-    // Capturing from FM TUNER output is not controlled by OP_RECORD_AUDIO
+    // Capturing from FM TUNER output is not controlled by an app op
     // because it does not affect users privacy as does capturing from an actual microphone.
     if (attr.source == AUDIO_SOURCE_FM_TUNER) {
         ALOGV("not muting FM TUNER capture for uid %d", identity.uid);
@@ -2227,12 +2227,12 @@
             || checkedIdentity.packageName.value().size() == 0) {
         return nullptr;
     }
-    return new OpRecordAudioMonitor(checkedIdentity);
+    return new OpRecordAudioMonitor(checkedIdentity, getOpForSource(attr.source));
 }
 
 AudioFlinger::RecordThread::OpRecordAudioMonitor::OpRecordAudioMonitor(
-        const Identity& identity)
-        : mHasOpRecordAudio(true), mIdentity(identity)
+        const Identity& identity, int32_t appOp)
+        : mHasOp(true), mIdentity(identity), mAppOp(appOp)
 {
 }
 
@@ -2246,36 +2246,36 @@
 
 void AudioFlinger::RecordThread::OpRecordAudioMonitor::onFirstRef()
 {
-    checkRecordAudio();
+    checkOp();
     mOpCallback = new RecordAudioOpCallback(this);
-    ALOGV("start watching OP_RECORD_AUDIO for %s", mIdentity.toString().c_str());
-    mAppOpsManager.startWatchingMode(AppOpsManager::OP_RECORD_AUDIO,
+    ALOGV("start watching op %d for %s", mAppOp, mIdentity.toString().c_str());
+    mAppOpsManager.startWatchingMode(mAppOp,
         VALUE_OR_FATAL(aidl2legacy_string_view_String16(mIdentity.packageName.value_or(""))),
         mOpCallback);
 }
 
-bool AudioFlinger::RecordThread::OpRecordAudioMonitor::hasOpRecordAudio() const {
-    return mHasOpRecordAudio.load();
+bool AudioFlinger::RecordThread::OpRecordAudioMonitor::hasOp() const {
+    return mHasOp.load();
 }
 
-// Called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback
-// and in onFirstRef()
+// Called by RecordAudioOpCallback when the app op corresponding to this OpRecordAudioMonitor
+// is updated in AppOp callback and in onFirstRef()
 // Note this method is never called (and never to be) for audio server / root track
 // due to the UID in createIfNeeded(). As a result for those record track, it's:
 // - not called from constructor,
 // - not called from RecordAudioOpCallback because the callback is not installed in this case
-void AudioFlinger::RecordThread::OpRecordAudioMonitor::checkRecordAudio()
+void AudioFlinger::RecordThread::OpRecordAudioMonitor::checkOp()
 {
 
-    const int32_t mode = mAppOpsManager.checkOp(AppOpsManager::OP_RECORD_AUDIO,
+    const int32_t mode = mAppOpsManager.checkOp(mAppOp,
             mIdentity.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
                 mIdentity.packageName.value_or(""))));
     const bool hasIt =  (mode == AppOpsManager::MODE_ALLOWED);
     // verbose logging only log when appOp changed
-    ALOGI_IF(hasIt != mHasOpRecordAudio.load(),
-            "OP_RECORD_AUDIO missing, %ssilencing record %s",
-            hasIt ? "un" : "", mIdentity.toString().c_str());
-    mHasOpRecordAudio.store(hasIt);
+    ALOGI_IF(hasIt != mHasOp.load(),
+            "App op %d missing, %ssilencing record %s",
+            mAppOp, hasIt ? "un" : "", mIdentity.toString().c_str());
+    mHasOp.store(hasIt);
 
 }
 
@@ -2286,12 +2286,12 @@
 void AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op,
             const String16& packageName) {
     UNUSED(packageName);
-    if (op != AppOpsManager::OP_RECORD_AUDIO) {
-        return;
-    }
     sp<OpRecordAudioMonitor> monitor = mMonitor.promote();
     if (monitor != NULL) {
-        monitor->checkRecordAudio();
+        if (op != monitor->getOp()) {
+            return;
+        }
+        monitor->checkOp();
     }
 }
 
@@ -2661,7 +2661,7 @@
         return true;
     }
     // The monitor is only created for record tracks that can be silenced.
-    return mOpRecordAudioMonitor ? !mOpRecordAudioMonitor->hasOpRecordAudio() : false;
+    return mOpRecordAudioMonitor ? !mOpRecordAudioMonitor->hasOp() : false;
 }
 
 status_t AudioFlinger::RecordThread::RecordTrack::getActiveMicrophones(
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 551013f..b9c715e 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -580,7 +580,7 @@
     // Capturing from FM_TUNER source is controlled by captureTunerAudioInputAllowed() and
     // captureAudioOutputAllowed() (deprecated) as this does not affect users privacy
     // as does capturing from an actual microphone.
-    if (!(recordingAllowed(adjIdentity) || attr.source == AUDIO_SOURCE_FM_TUNER)) {
+    if (!(recordingAllowed(adjIdentity, attr.source) || attr.source == AUDIO_SOURCE_FM_TUNER)) {
         ALOGE("%s permission denied: recording not allowed for %s",
                 __func__, adjIdentity.toString().c_str());
         return binderStatusFromStatusT(PERMISSION_DENIED);
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index b80fe57..8b64134 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -131,10 +131,10 @@
 void MediaTranscodingService::instantiate() {
     std::shared_ptr<MediaTranscodingService> service =
             ::ndk::SharedRefBase::make<MediaTranscodingService>();
-    if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
-        // Once service is started, we want it to stay even is client side perished.
-        AServiceManager_forceLazyServicesPersist(true /*persist*/);
-        (void)AServiceManager_registerLazyService(service->asBinder().get(), getServiceName());
+    binder_status_t status =
+            AServiceManager_addService(service->asBinder().get(), getServiceName());
+    if (status != STATUS_OK) {
+        return;
     }
 }
 
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
index 0cb2fad..20e4bfb 100644
--- a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -481,7 +481,7 @@
         // Need thread pool to receive callbacks, otherwise oneway callbacks are
         // silently ignored.
         ABinderProcess_startThreadPool();
-        ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.transcoding"));
+        ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
         mService = IMediaTranscodingService::fromBinder(binder);
         if (mService == nullptr) {
             ALOGE("Failed to connect to the media.trascoding service.");