android系统 默认提示音控制流程

以下是源码分析流程:
第一步:
frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
   1.
    public void onCreate() {
        super.onCreate();
        Log.v(TAG, "SystemUIApplication created.");
        // This line is used to setup Dagger's dependency injection and should be kept at the
        // top of this method.
        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
                Trace.TRACE_TAG_APP);
        log.traceBegin("DependencyInjection");
        mContextAvailableCallback.onContextAvailable(this);
        mRootComponent = SystemUIFactory.getInstance().getRootComponent();
        mComponentHelper = mRootComponent.getContextComponentHelper();
        mBootCompleteCache = mRootComponent.provideBootCacheImpl();
        log.traceEnd();

        // Set the application theme that is inherited by all services. Note that setting the
        // application theme in the manifest does only work for activities. Keep this in sync with
        // the theme set there.
        setTheme(R.style.Theme_SystemUI);

        if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
            IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
            bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
            registerReceiver(new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (mBootCompleteCache.isBootComplete()) return;

                    if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
                    unregisterReceiver(this);
                    mBootCompleteCache.setBootComplete();
                    if (mServicesStarted) {
                        final int N = mServices.length;
                        for (int i = 0; i < N; i++) {
                            mServices[i].onBootCompleted();
                        }
                    }
                }
            }, bootCompletedFilter);

            IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
            registerReceiver(new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
                        if (!mBootCompleteCache.isBootComplete()) return;
                        // Update names of SystemUi notification channels
                        NotificationChannels.createAll(context);
                    }
                }
            }, localeChangedFilter);
        } else {
            // We don't need to startServices for sub-process that is doing some tasks.
            // (screenshots, sweetsweetdesserts or tuner ..)
            String processName = ActivityThread.currentProcessName();
            ApplicationInfo info = getApplicationInfo();
            if (processName != null && processName.startsWith(info.processName + ":")) {
                return;
            }
            // For a secondary user, boot-completed will never be called because it has already
            // been broadcasted on startup for the primary SystemUI process.  Instead, for
            // components which require the SystemUI component to be initialized per-user, we
            // start those components now for the current non-system user.
            startSecondaryUserServicesIfNeeded();   会走这里
        }
    }


    2.
        void startSecondaryUserServicesIfNeeded() {
        String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponentsPerUser(   //这里从config.xml文件里面获取服务名称
                getResources());
        startServicesIfNeeded(/* metricsPrefix= */ "StartSecondaryServices", names);
    }

   3.
   frameworks/base/packages/SystemUI/res/values/config.xml
    <string-array name="config_systemUIServiceComponents" translatable="false">
        <item>com.android.systemui.util.NotificationChannels</item>
        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
        <item>com.android.systemui.recents.Recents</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.stackdivider.Divider</item>
        <item>com.android.systemui.statusbar.phone.StatusBar</item>
        <item>com.android.systemui.usb.StorageNotification</item>
        <item>com.android.systemui.power.PowerUI</item>
        <item>com.android.systemui.media.RingtonePlayer</item>
        <item>com.android.systemui.keyboard.KeyboardUI</item>
        <item>com.android.systemui.pip.PipUI</item>
        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
        <item>@string/config_systemUIVendorServiceComponent</item>
        <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
        <item>com.android.systemui.LatencyTester</item>
        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
        <item>com.android.systemui.ScreenDecorations</item>
        <item>com.android.systemui.biometrics.AuthController</item>
        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
        <item>com.android.systemui.SizeCompatModeActivityController</item>
        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
        <item>com.android.systemui.theme.ThemeOverlayController</item>
        <item>com.android.systemui.accessibility.WindowMagnification</item>
        <item>com.android.systemui.accessibility.SystemActions</item>
        <item>com.android.systemui.toast.ToastUI</item>
    </string-array>


    4.
    private void startServicesIfNeeded(String metricsPrefix, String[] services) {
        if (mServicesStarted) {
            return;
        }
        mServices = new SystemUI[services.length];

        if (!mBootCompleteCache.isBootComplete()) {
            // check to see if maybe it was already completed long before we began
            // see ActivityManagerService.finishBooting()
            if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
                mBootCompleteCache.setBootComplete();
                if (DEBUG) {
                    Log.v(TAG, "BOOT_COMPLETED was already sent");
                }
            }
        }

        final DumpManager dumpManager = mRootComponent.createDumpManager();

        Log.v(TAG, "Starting SystemUI services for user " +
                Process.myUserHandle().getIdentifier() + ".");
        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
                Trace.TRACE_TAG_APP);
        log.traceBegin(metricsPrefix);
        final int N = services.length;
        for (int i = 0; i < N; i++) {
            String clsName = services[i];
            if (DEBUG) Log.d(TAG, "loading: " + clsName);
            log.traceBegin(metricsPrefix + clsName);
            long ti = System.currentTimeMillis();
            try {
                SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
                if (obj == null) {
                    Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                    obj = (SystemUI) constructor.newInstance(this);
                }
                mServices[i] = obj;
            } catch (ClassNotFoundException
                    | NoSuchMethodException
                    | IllegalAccessException
                    | InstantiationException
                    | InvocationTargetException ex) {
                throw new RuntimeException(ex);
            }

            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
            mServices[i].start();   这里会启动RingtonePlayer 服务
            log.traceEnd();

            // Warn if initialization of component takes too long
            ti = System.currentTimeMillis() - ti;
            if (ti > 1000) {
                Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
            }
            if (mBootCompleteCache.isBootComplete()) {
                mServices[i].onBootCompleted();
            }

            dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
        }
        mRootComponent.getInitController().executePostInitTasks();
        log.traceEnd();

        mServicesStarted = true;
    }


第二步:
frameworks/base/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java

  public void start() {
        mAsyncPlayer.setUsesWakeLock(mContext);

        mAudioService = IAudioService.Stub.asInterface(
                ServiceManager.getService(Context.AUDIO_SERVICE));
        try {
            mAudioService.setRingtonePlayer(mCallback);   mAudioService设置IRingtonePlayer的回调
        } catch (RemoteException e) {
            Log.e(TAG, "Problem registering RingtonePlayer: " + e);
        }
    }

 

    @Override
        public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa) {
            if (LOGD) Log.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                throw new SecurityException("Async playback only available from system UID.");
            }
            if (UserHandle.ALL.equals(user)) {
                user = UserHandle.SYSTEM;
            }
       Log.e(TAG, Log.getStackTraceString(new Throwable()));
            mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);
        }

 

第三步:
frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
 
          if (mAssistants.isEnabled()) {
                    mAssistants.onNotificationEnqueuedLocked(r);
                    mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
                            DELAY_FOR_ASSISTANT_TIME);
                } else {
                    mHandler.post(new PostNotificationRunnable(r.getKey()));  这里开始PostNotificationRunnable 线程运行
                }

 

  final boolean isPackageSuspended =
                            isPackagePausedOrSuspended(r.getSbn().getPackageName(), r.getUid());
                    r.setHidden(isPackageSuspended);
    int buzzBeepBlinkLoggingCode = 0;
                    if (!r.isHidden()) {
                        buzzBeepBlinkLoggingCode = buzzBeepBlinkLocked(r);
                    }

    

 

 int buzzBeepBlinkLocked(NotificationRecord record) {
        Log.e(TAG,"zhanghui                  buzzBeepBlinkLocked   1.0");
        if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
            return 0;
        }
        boolean buzz = false;
        boolean beep = false;
        boolean blink = false;

        final Notification notification = record.getSbn().getNotification();
        final String key = record.getKey();
            Log.e(TAG,"zhanghui                  buzzBeepBlinkLocked   1.0.0");
        // Should this notification make noise, vibe, or use the LED?
        final boolean aboveThreshold =
                mIsAutomotive
                        ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
                        : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
        // Remember if this notification already owns the notification channels.
        boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
        boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
        // These are set inside the conditional if the notification is allowed to make noise.
        boolean hasValidVibrate = false;
        boolean hasValidSound = false;
        boolean sentAccessibilityEvent = false;
       Log.e(TAG,"zhanghui                  buzzBeepBlinkLocked   1.1");
        // If the notification will appear in the status bar, it should send an accessibility event
        final boolean suppressedByDnd = record.isIntercepted()
                && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
        if (!record.isUpdate
                && record.getImportance() > IMPORTANCE_MIN
                && !suppressedByDnd) {
            sendAccessibilityEvent(notification, record.getSbn().getPackageName());
            sentAccessibilityEvent = true;
        }
     Log.e(TAG,"zhanghui                  buzzBeepBlinkLocked   1.2 aboveThreshold="+aboveThreshold);
     Log.e(TAG,"zhanghui                  buzzBeepBlinkLocked   1.2  isNotificationForCurrentUser(record)="+ isNotificationForCurrentUser(record));
        if (aboveThreshold && isNotificationForCurrentUser(record)) {
            Log.e(TAG,"zhanghui                  buzzBeepBlinkLocked   1.2 mSystemReady="+mSystemReady);
        if(mAudioManager != null){
        Log.e(TAG,"zhanghui                  buzzBeepBlinkLocked    mAudioManager is true");
       }
            if (mSystemReady && mAudioManager != null) {
                Uri soundUri = record.getSound();
                hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
                long[] vibration = record.getVibration();
                // Demote sound to vibration if vibration missing & phone in vibration mode.
                if (vibration == null
                        && hasValidSound
                        && (mAudioManager.getRingerModeInternal()
                        == AudioManager.RINGER_MODE_VIBRATE)
                        && mAudioManager.getStreamVolume(
                        AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
                    vibration = mFallbackVibrationPattern;
                }
                hasValidVibrate = vibration != null;
                boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
        Log.e(TAG,"zhanghui     hasAudibleAlert="+hasAudibleAlert);
                if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {  //shouldMuteNotificationLocked这里很关键,高通原生第一次升级默认没有提示音(比如:蓝牙传输接收文件没有提示音)
                    if (!sentAccessibilityEvent) {
                        sendAccessibilityEvent(notification, record.getSbn().getPackageName());
                        sentAccessibilityEvent = true;
                    }
                    if (DBG) Slog.v(TAG, "Interrupting!");
         Log.e(TAG,"zhanghui                  buzzBeepBlinkLocked   1.2 hasValidSound="+hasValidSound);
                    if (hasValidSound) {
                        if (isInCall()) {
                            playInCallNotification();
                            beep = true;
                        } else {
                            beep = playSound(record, soundUri);  跑这里调用
                        }
                        if(beep) {
                            mSoundNotificationKey = key;
                        }
                    }

                    final boolean ringerModeSilent =
                            mAudioManager.getRingerModeInternal()
                                    == AudioManager.RINGER_MODE_SILENT;
                    if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
                        buzz = playVibration(record, vibration, hasValidSound);
                        if(buzz) {
                            mVibrateNotificationKey = key;
                        }
                    }
                } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
                    hasValidSound = false;
                }
            }
        }
        // If a notification is updated to remove the actively playing sound or vibrate,
        // cancel that feedback now
        if (wasBeep && !hasValidSound) {
            clearSoundLocked();
        }
        if (wasBuzz && !hasValidVibrate) {
            clearVibrateLocked();
        }

        // light
        // release the light
        boolean wasShowLights = mLights.remove(key);
        if (canShowLightsLocked(record, aboveThreshold)) {
            mLights.add(key);
            updateLightsLocked();
            if (mUseAttentionLight && mAttentionLight != null) {
                mAttentionLight.pulse();
            }
            blink = true;
        } else if (wasShowLights) {
            updateLightsLocked();
        }
        final int buzzBeepBlink = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0);
        if (buzzBeepBlink > 0) {
            // Ignore summary updates because we don't display most of the information.
            if (record.getSbn().isGroup() && record.getSbn().getNotification().isGroupSummary()) {
                if (DEBUG_INTERRUPTIVENESS) {
                    Slog.v(TAG, "INTERRUPTIVENESS: "
                            + record.getKey() + " is not interruptive: summary");
                }
            } else if (record.canBubble()) {
                if (DEBUG_INTERRUPTIVENESS) {
                    Slog.v(TAG, "INTERRUPTIVENESS: "
                            + record.getKey() + " is not interruptive: bubble");
                }
            } else {
                record.setInterruptive(true);
                if (DEBUG_INTERRUPTIVENESS) {
                    Slog.v(TAG, "INTERRUPTIVENESS: "
                            + record.getKey() + " is interruptive: alerted");
                }
            }
            MetricsLogger.action(record.getLogMaker()
                    .setCategory(MetricsEvent.NOTIFICATION_ALERT)
                    .setType(MetricsEvent.TYPE_OPEN)
                    .setSubtype(buzzBeepBlink));
            EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
        }
        record.setAudiblyAlerted(buzz || beep);
        return buzzBeepBlink;
    }

 


 private boolean playSound(final NotificationRecord record, Uri soundUri) {
        boolean looping = (record.getNotification().flags & FLAG_INSISTENT) != 0;
        // play notifications if there is no user of exclusive audio focus
        // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
        //   VIBRATE ringer mode)
        if (!mAudioManager.isAudioFocusExclusive()
                && (mAudioManager.getStreamVolume(
                        AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
            final long identity = Binder.clearCallingIdentity();
            try {
                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
                if (player != null) {
                    if (true) Slog.v(TAG, "zhanghui  Playing sound " + soundUri
                            + " with attributes " + record.getAudioAttributes());
            Log.e(TAG, Log.getStackTraceString(new Throwable()));
                    player.playAsync(soundUri, record.getSbn().getUser(), looping,   这里跑到第二步的RingtonePlayer回调函数的playAsync,这里传入的soundUri 就是后面播放的提示音文件缓存
                            record.getAudioAttributes());
                    return true;
                }
            } catch (RemoteException e) {
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
        return false;
    }

第四步:
frameworks/base/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java

  public void start() {
        mAsyncPlayer.setUsesWakeLock(mContext);

        mAudioService = IAudioService.Stub.asInterface(
                ServiceManager.getService(Context.AUDIO_SERVICE));
        try {
            mAudioService.setRingtonePlayer(mCallback);   mAudioService设置IRingtonePlayer的回调
        } catch (RemoteException e) {
            Log.e(TAG, "Problem registering RingtonePlayer: " + e);
        }
    }

 

    @Override
        public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa) {
            if (LOGD) Log.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                throw new SecurityException("Async playback only available from system UID.");
            }
            if (UserHandle.ALL.equals(user)) {
                user = UserHandle.SYSTEM;
            }
       Log.e(TAG, Log.getStackTraceString(new Throwable()));
            mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);  这里跑到NotificationPlayer类的play()
        }

frameworks/base/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java


 public void play(Context context, Uri uri, boolean looping, AudioAttributes attributes) {
        if (DEBUG) { Log.d(mTag, "play uri=" + uri.toString()); }
        Command cmd = new Command();
        cmd.requestTime = SystemClock.uptimeMillis();
        cmd.code = PLAY;
        cmd.context = context;
        cmd.uri = uri;
        cmd.looping = looping;
        cmd.attributes = attributes;
        synchronized (mCmdQueue) {
            enqueueLocked(cmd);
            mState = PLAY;
        }
    }

 

        private void enqueueLocked(Command cmd) {
        mCmdQueue.add(cmd);
        if (mThread == null) {
            acquireWakeLock();
            mThread = new CmdThread();
            mThread.start();
        }
    }


      private final class CmdThread extends java.lang.Thread {
        CmdThread() {
            super("NotificationPlayer-" + mTag);
        }

        public void run() {
            while (true) {
                Command cmd = null;

                synchronized (mCmdQueue) {
                    if (DEBUG) Log.d(mTag, "RemoveFirst");
                    cmd = mCmdQueue.removeFirst();
                }

                switch (cmd.code) {
                case PLAY:
                    if (DEBUG) Log.d(mTag, "PLAY");
                    startSound(cmd);  这里跑到CreationAndCompletionThread 线程
                    break;
                case STOP:
                    if (DEBUG) Log.d(mTag, "STOP");
                    final MediaPlayer mp;
                    synchronized (mPlayerLock) {
                        mp = mPlayer;
                        mPlayer = null;
                    }
                    if (mp != null) {
                        long delay = SystemClock.uptimeMillis() - cmd.requestTime;
                        if (delay > 1000) {
                            Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
                        }
                        try {
                            mp.stop();
                        } catch (Exception e) { }
                        mp.release();
                        synchronized(mQueueAudioFocusLock) {
                            if (mAudioManagerWithAudioFocus != null) {
                                if (DEBUG) { Log.d(mTag, "in STOP: abandonning AudioFocus"); }
                                mAudioManagerWithAudioFocus.abandonAudioFocus(null);
                                mAudioManagerWithAudioFocus = null;
                            }
                        }
                        synchronized (mCompletionHandlingLock) {
                            if ((mLooper != null) &&
                                    (mLooper.getThread().getState() != Thread.State.TERMINATED))
                            {
                                if (DEBUG) { Log.d(mTag, "in STOP: quitting looper "+ mLooper); }
                                mLooper.quit();
                            }
                        }
                    } else {
                        Log.w(mTag, "STOP command without a player");
                    }
                    break;
                }

 


 private final class CreationAndCompletionThread extends Thread {
        public Command mCmd;
        public CreationAndCompletionThread(Command cmd) {
            super();
            mCmd = cmd;
        }

        public void run() {
            Looper.prepare();
            // ok to modify mLooper as here we are
            // synchronized on mCompletionHandlingLock due to the Object.wait() in startSound(cmd)
            mLooper = Looper.myLooper();
            if (DEBUG) Log.d(mTag, "in run: new looper " + mLooper);
            MediaPlayer player = null;
            synchronized(this) {
                AudioManager audioManager =
                    (AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE);
                try {
                    player = new MediaPlayer();
                    if (mCmd.attributes == null) {
                        mCmd.attributes = new AudioAttributes.Builder()
                                .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                                .build();
                    }
                    player.setAudioAttributes(mCmd.attributes);
                    player.setDataSource(mCmd.context, mCmd.uri);  这里调用了MediaPlayer里面的setDataSource
                    player.setLooping(mCmd.looping);
                    player.setOnCompletionListener(NotificationPlayer.this);
                    player.setOnErrorListener(NotificationPlayer.this);
                    player.prepare();
                    if ((mCmd.uri != null) && (mCmd.uri.getEncodedPath() != null)
                            && (mCmd.uri.getEncodedPath().length() > 0)) {
                        if (!audioManager.isMusicActiveRemotely()) {
                            synchronized (mQueueAudioFocusLock) {
                                if (mAudioManagerWithAudioFocus == null) {
                                    if (DEBUG) Log.d(mTag, "requesting AudioFocus");
                                    int focusGain = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
                                    if (mCmd.looping) {
                                        focusGain = AudioManager.AUDIOFOCUS_GAIN;
                                    }
                                    mNotificationRampTimeMs = audioManager.getFocusRampTimeMs(
                                            focusGain, mCmd.attributes);
                                    audioManager.requestAudioFocus(null, mCmd.attributes,
                                                focusGain, 0);
                                    mAudioManagerWithAudioFocus = audioManager;
                                } else {
                                    if (DEBUG) Log.d(mTag, "AudioFocus was previously requested");
                                }
                            }
                        }
                    }
                    // FIXME Having to start a new thread so we can receive completion callbacks
                    //  is wrong, as we kill this thread whenever a new sound is to be played. This
                    //  can lead to AudioFocus being released too early, before the second sound is
                    //  done playing. This class should be modified to use a single thread, on which
                    //  command are issued, and on which it receives the completion callbacks.
                    if (DEBUG)  { Log.d(mTag, "notification will be delayed by "
                            + mNotificationRampTimeMs + "ms"); }
                    try {
                        Thread.sleep(mNotificationRampTimeMs);
                    } catch (InterruptedException e) {
                        Log.e(mTag, "Exception while sleeping to sync notification playback"
                                + " with ducking", e);
                    }
                    player.start();
                    if (DEBUG) { Log.d(mTag, "player.start"); }
                } catch (Exception e) {
                    if (player != null) {
                        player.release();
                        player = null;
                    }
                    Log.w(mTag, "error loading sound for " + mCmd.uri, e);
                    // playing the notification didn't work, revert the focus request
                    abandonAudioFocusAfterError();
                }
                final MediaPlayer mp;
                synchronized (mPlayerLock) {
                    mp = mPlayer;
                    mPlayer = player;
                }
                if (mp != null) {
                    if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
                    mp.release();
                }
                this.notify();
            }
            Looper.loop();
        }
    };

frameworks/base/media/java/android/media/MediaPlayer.java


 private boolean attemptDataSource(ContentResolver resolver, Uri uri) {
        try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {   这里跑到了ContentResolver里面的openAssetFileDescriptor
            setDataSource(afd);
            return true;
        } catch (NullPointerException | SecurityException | IOException ex) {
            return false;
        }
    }


    public void setDataSource(String path)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(path, null, null);
    }

 


  public void setDataSource(@NonNull Context context, @NonNull Uri uri)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(context, uri, null, null);
    }

 


      private void setDataSource(String path, String[] keys, String[] values,
            List<HttpCookie> cookies)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        final Uri uri = Uri.parse(path);
        final String scheme = uri.getScheme();

        if ("file".equals(scheme)) {
            path = uri.getPath();
    Log.e(TAG,"zhanghui              path="+path);
        } else if (scheme != null) {
            // handle non-file sources
            nativeSetDataSource(      
                MediaHTTPService.createHttpServiceBinderIfNecessary(path, cookies),
                path,
                keys,
                values);
            return;
        }

        final File file = new File(path);
        try (FileInputStream is = new FileInputStream(file)) {
    Log.e(TAG,"zhanghui              is.getFD()="+is.getFD());
            setDataSource(is.getFD());
        }
    }


frameworks/base/core/java/android/content/ContentResolver.java

    public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
            @NonNull String mode) throws FileNotFoundException {
        return openAssetFileDescriptor(uri, mode, null);
    }


 public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
            @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
                    throws FileNotFoundException {
        Objects.requireNonNull(uri, "uri");
        Objects.requireNonNull(mode, "mode");

        try {
            if (mWrapped != null) return mWrapped.openAssetFile(uri, mode, cancellationSignal);
        } catch (RemoteException e) {
            return null;
        }

        String scheme = uri.getScheme();
        if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
            if (!"r".equals(mode)) {
                throw new FileNotFoundException("Can't write resources: " + uri);
            }
            OpenResourceIdResult r = getResourceId(uri);
            try {
                return r.r.openRawResourceFd(r.id);
            } catch (Resources.NotFoundException ex) {
                throw new FileNotFoundException("Resource does not exist: " + uri);
            }
        } else if (SCHEME_FILE.equals(scheme)) {
            ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
                    new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode));
            return new AssetFileDescriptor(pfd, 0, -1);
        } else {
            if ("r".equals(mode)) {
                return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
            } else {
                IContentProvider unstableProvider = acquireUnstableProvider(uri);
                if (unstableProvider == null) {
                    throw new FileNotFoundException("No content provider: " + uri);
                }
                IContentProvider stableProvider = null;
                AssetFileDescriptor fd = null;

                try {
                    ICancellationSignal remoteCancellationSignal = null;
                    if (cancellationSignal != null) {
                        cancellationSignal.throwIfCanceled();
                        remoteCancellationSignal = unstableProvider.createCancellationSignal();
                        cancellationSignal.setRemote(remoteCancellationSignal);
                    }

                    try {
                        fd = unstableProvider.openAssetFile(
                                mPackageName, mAttributionTag, uri, mode,
                                remoteCancellationSignal);
                        if (fd == null) {
                            // The provider will be released by the finally{} clause
                            return null;
                        }
                    } catch (DeadObjectException e) {
                        // The remote process has died...  but we only hold an unstable
                        // reference though, so we might recover!!!  Let's try!!!!
                        // This is exciting!!1!!1!!!!1
                        unstableProviderDied(unstableProvider);
                        stableProvider = acquireProvider(uri);
                        if (stableProvider == null) {
                            throw new FileNotFoundException("No content provider: " + uri);
                        }
                        fd = stableProvider.openAssetFile(
                                mPackageName, mAttributionTag, uri, mode, remoteCancellationSignal);
                        if (fd == null) {
                            // The provider will be released by the finally{} clause
                            return null;
                        }
                    }

                    if (stableProvider == null) {
                        stableProvider = acquireProvider(uri);
                    }
                    releaseUnstableProvider(unstableProvider);
                    unstableProvider = null;
                    ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
                            fd.getParcelFileDescriptor(), stableProvider);

                    // Success!  Don't release the provider when exiting, let
                    // ParcelFileDescriptorInner do that when it is closed.
                    stableProvider = null;

                    return new AssetFileDescriptor(pfd, fd.getStartOffset(),
                            fd.getDeclaredLength());

                } catch (RemoteException e) {
                    // Whatever, whatever, we'll go away.
                    throw new FileNotFoundException(
                            "Failed opening content provider: " + uri);
                } catch (FileNotFoundException e) {
                    throw e;
                } finally {
                    if (cancellationSignal != null) {
                        cancellationSignal.setRemote(null);
                    }
                    if (stableProvider != null) {
                        releaseProvider(stableProvider);
                    }
                    if (unstableProvider != null) {
                        releaseUnstableProvider(unstableProvider);
                    }
                }
            }
        }
    }

 

上一篇:242.有效的字母异位词


下一篇:Kafka成长3:Producer 元数据拉取源码原理(上)