天天看点

hdmi hotplug

hdmi插入,信号源app hdmi连接logo显示

hdmi拔掉,信号源app hdmi连接logo不显示

代码流程分析。

一,

hdmi在插入时,5v检测会探测到是哪个hdmi插入的。

我猜测tv_input.amlogic.so会一直read这个状态。

tv_input( 4331): TvCallback::onTvEvent  source = 7, status = 0

hdmi拔掉的时候,amlogic不开源的tv_input.amlogic.so向上层callback一个消息。source=7 代表是hdmi3,status = 0代表拔掉。

vendor/amlogic/apps/TvLibRelease/tv_input/tv_input.cpp

hdmi hotplug

static int notify_HDMI_device_available(tv_input_private_t *priv, tv_source_input_t source_input, uint32_t port_id, int type)

{

        tv_input_event_t event;

        event.device_info.device_id = source_input;

        event.device_info.type = TV_INPUT_TYPE_HDMI;

        event.type = type;

        event.device_info.hdmi.port_id = port_id;

        event.device_info.audio_type = AUDIO_DEVICE_NONE;

        event.device_info.audio_address = NULL;

        priv->callback->notify(&priv->device, &event, priv->callback_data);

        return 0;

}

二,frameworks/base/services/core/jni/com_android_server_tv_TvInputHal.cpp  

void JTvInputHal::notify(

        tv_input_device_t* dev, tv_input_event_t* event, void* data) {

    JTvInputHal* thiz = (JTvInputHal*)data;

    ALOGE("JTvInputHal notify sendMessage"+event->type);

    thiz->mLooper->sendMessage(new NotifyHandler(thiz, event), event->type);

}

void JTvInputHal::NotifyHandler::handleMessage(const Message& message) {

    switch (mEvent.type) {

        case TV_INPUT_EVENT_DEVICE_AVAILABLE: {

            mHal->onDeviceAvailable(mEvent.device_info);

        } break;

        case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {

            ALOGE("TV_INPUT_EVENT_DEVICE_UNAVAILABLE device_id"+mEvent.device_info.device_id);

                                                        mHal->onDeviceUnavailable(mEvent.device_info.device_id);

        } break;

        case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: {

            mHal->onStreamConfigurationsChanged(mEvent.device_info.device_id);

        } break;

        case TV_INPUT_EVENT_CAPTURE_SUCCEEDED: {

            mHal->onCaptured(mEvent.capture_result.device_id,

                             mEvent.capture_result.stream_id,

                             mEvent.capture_result.seq,

                             true );

        } break;

        case TV_INPUT_EVENT_CAPTURE_FAILED: {

            mHal->onCaptured(mEvent.capture_result.device_id,

                             mEvent.capture_result.stream_id,

                             mEvent.capture_result.seq,

                             false );

        } break;

        default:

            ALOGE("Unrecognizable event");

    }

}

走到这,  case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {

            ALOGE("TV_INPUT_EVENT_DEVICE_UNAVAILABLE device_id"+mEvent.device_info.device_id);

                                                        mHal->onDeviceUnavailable(mEvent.device_info.device_id);

        } break;

void JTvInputHal::onDeviceUnavailable(int deviceId) {

    {

        Mutex::Autolock autoLock(&mLock);

        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);

        for (size_t i = 0; i < connections.size(); ++i) {

            removeStream(deviceId, connections.keyAt(i));

        }

        connections.clear();

        mConnections.removeItem(deviceId);

    }

    JNIEnv* env = AndroidRuntime::getJNIEnv();

     ALOGE("JTvInputHal onDeviceUnavailable"+deviceId);

    env->CallVoidMethod(

            mThiz,

            gTvInputHalClassInfo.deviceUnavailable,

            deviceId);

}

ET_METHOD_ID(

            gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");

三,

frameworks/base/services/core/java/com/android/server/tv/TvInputHal.java 

 private void deviceUnavailableFromNative(int deviceId) {

             Slog.e(TAG, "deviceUnavailableFromNative"+deviceId);

            mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();

    }

 public boolean handleMessage(Message msg) {

        switch (msg.what) {

            case EVENT_DEVICE_AVAILABLE: {

                TvStreamConfig[] configs;

                TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj;

                synchronized (mLock) {

                    retrieveStreamConfigsLocked(info.getDeviceId());

                    if (DEBUG) {

                        Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info);

                    }

                    configs = mStreamConfigs.get(info.getDeviceId());

                }

                mCallback.onDeviceAvailable(info, configs);

                break;

            }

            case EVENT_DEVICE_UNAVAILABLE: {

                int deviceId = msg.arg1;

                if (DEBUG) {

                    Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId);

                }

                mCallback.onDeviceUnavailable(deviceId);

                break;

            }

mCallback.onDeviceUnavailable

四, frameworks/base/services/core/java/com/android/server/tv/TvInputHardwareManager.java

 @Override

    public void onDeviceUnavailable(int deviceId) {

        synchronized (mLock) {

            Connection connection = mConnections.get(deviceId);

            if (connection == null) {

                Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId);

                return;

            }

            connection.resetLocked(null, null, null, null, null);

            mConnections.remove(deviceId);

            buildHardwareListLocked();

            TvInputHardwareInfo info = connection.getHardwareInfoLocked();

            if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) {

                // Remove HDMI devices linked with this hardware.

                for (Iterator<HdmiDeviceInfo> it = mHdmiDeviceList.iterator(); it.hasNext();) {

                    HdmiDeviceInfo deviceInfo = it.next();

                    if (deviceInfo.getPortId() == info.getHdmiPortId()) {

             Slog.e(TAG, "onDeviceUnavailable HDMI_DEVICE_REMOVED");

                        mHandler.obtainMessage(ListenerHandler.HDMI_DEVICE_REMOVED, 0, 0,

                                deviceInfo).sendToTarget();

                        it.remove();

                    }

                }

            }

             Slog.e(TAG, "onDeviceUnavailable HARDWARE_DEVICE_REMOVED"+deviceId);

            mHandler.obtainMessage(

                    ListenerHandler.HARDWARE_DEVICE_REMOVED, 0, 0, info).sendToTarget();

        }

    }

        @Override

        public final void handleMessage(Message msg) {

            switch (msg.what) {

                case STATE_CHANGED: {

                    String inputId = (String) msg.obj;

                    int state = msg.arg1;

                    mListener.onStateChanged(inputId, state);

                    break;

                }

                case HARDWARE_DEVICE_ADDED: {

                    TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj;

                    mListener.onHardwareDeviceAdded(info);

                    break;

                }

                case HARDWARE_DEVICE_REMOVED: {

                    Slog.e(TAG, "HARDWARE_DEVICE_REMOVED " );

                    TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj;

                    mListener.onHardwareDeviceRemoved(info);

                    break;

                }

五,frameworks/base$ vi services/core/java/com/android/server/tv/TvInputManagerService.java

@Override

        public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {

            synchronized (mLock) {

                UserState userState = getUserStateLocked(mCurrentUserId);

                // Broadcast the event to all hardware inputs.

                for (ServiceState serviceState : userState.serviceStateMap.values()) {

                    if (!serviceState.isHardware || serviceState.service == null) continue;

                    try {

                        Slog.e(TAG, "onHardwareDeviceRemoved");

                        serviceState.service.notifyHardwareRemoved(info);

                    } catch (RemoteException e) {

                        Slog.e(TAG, "error in notifyHardwareRemoved", e);

                    }

                }

            }

        }

六 frameworks/base$ vim media/java/android/media/tv/TvInputService.java

@Override

            public void notifyHardwareRemoved(TvInputHardwareInfo hardwareInfo) {

                 Log.e(TAG, "notifyHardwareRemoved ");

                    mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_TV_INPUT,

                        hardwareInfo).sendToTarget();

            }

case DO_REMOVE_HARDWARE_TV_INPUT: {

                    TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;

                    String inputId = onHardwareRemoved(hardwareInfo);

                    Log.e(TAG, "DO_REMOVE_HARDWARE_TV_INPUT  inputId "+ inputId);

                    if (inputId != null) {

                        broadcastRemoveTvInput(inputId);

                    }

                    return;

                }

        private void broadcastRemoveTvInput(String inputId) {

            int n = mCallbacks.beginBroadcast();

            for (int i = 0; i < n; ++i) {

                try {

                    mCallbacks.getBroadcastItem(i).removeTvInput(inputId);

                } catch (RemoteException e) {

                    Log.e(TAG, "Error while broadcasting.", e);

                }

            }

            mCallbacks.finishBroadcast();

        }

frameworks/base$ vim services/core/java/com/android/server/tv/TvInputManagerService.java 

@Override

        public void removeTvInput(String inputId) {

            ensureHardwarePermission();

            synchronized (mLock) {

                ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);

                boolean removed = false;

                for (Iterator<TvInputInfo> it = serviceState.inputList.iterator();

                        it.hasNext(); ) {

                    if (it.next().getId().equals(inputId)) {

                        it.remove();

                        if(DEBUG){

                            Slog.d(TAG, "removeTvInput true");

                        }

                        removed = true;

//                        break; //鍉\═VInputService琚~][email protected]姝婚~G~M鍉P~P~N锛~LServiceState涓~Z~DinputList涓縹X瀛~X鍉\ㄧ~][email protected]鎫Wх~Z~D鎫U版~M紐L濡~B鎫^~\姝ゅDbreak浼~Z鎫\~I鍉H| 涓~M骞插[email protected]鐍Z~D鎫C~E鍉F碉紐L浠~N鑯@~L瀵艰~G寸~J舵[email protected]~A閪WX

                    }

                }

                if (removed) {

                    buildTvInputListLocked(mUserId, null);

                    Slog.e(TAG, "removeTvInput "+inputId);

                    mTvInputHardwareManager.removeTvInput(inputId);

                } else {

                    Slog.e(TAG, "failed to remove input " + inputId);

                }

            }

        }

    }

private void buildTvInputListLocked(int userId, String[] updatedPackages) {

        UserState userState = getUserStateLocked(userId);

        userState.packageSet.clear();

        if (DEBUG) Slog.d(TAG, "buildTvInputList");

        PackageManager pm = mContext.getPackageManager();

        List<ResolveInfo> services = pm.queryIntentServices(

                new Intent(TvInputService.SERVICE_INTERFACE),

                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);

        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();

        for (ResolveInfo ri : services) {

            ServiceInfo si = ri.serviceInfo;

            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {

                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "

                        + android.Manifest.permission.BIND_TV_INPUT);

                continue;

            }

            ComponentName component = new ComponentName(si.packageName, si.name);

            if (hasHardwarePermission(pm, component)) {

                ServiceState serviceState = userState.serviceStateMap.get(component);

                if (serviceState == null) {

                    // We see this hardware TV input service for the first time; we need to

                    // prepare the ServiceState object so that we can connect to the service and

                    // let it add TvInputInfo objects to mInputList if there's any.

                    serviceState = new ServiceState(component, userId);

                    userState.serviceStateMap.put(component, serviceState);

                    updateServiceConnectionLocked(component, userId);

                } else {

                    inputList.addAll(serviceState.inputList);

                }

            } else {

                try {

                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));

                } catch (XmlPullParserException | IOException e) {

                    Slog.e(TAG, "failed to load TV input " + si.name, e);

                    continue;

                }

            }

            userState.packageSet.add(si.packageName);

        }

        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();

        for (TvInputInfo info : inputList) {

            if (DEBUG) {

                Slog.d(TAG, "add " + info.getId());

            }

            TvInputState state = userState.inputMap.get(info.getId());

            if (state == null) {

                state = new TvInputState();

            }

            state.info = info;

            inputMap.put(info.getId(), state);

        }

        for (String inputId : inputMap.keySet()) {

            if (!userState.inputMap.containsKey(inputId)) {

                notifyInputAddedLocked(userState, inputId);

            } else if (updatedPackages != null) {

                // Notify the package updates

                ComponentName component = inputMap.get(inputId).info.getComponent();

                for (String updatedPackage : updatedPackages) {

                    if (component.getPackageName().equals(updatedPackage)) {

                        updateServiceConnectionLocked(component, userId);

                        Slog.e(TAG, "notifyInputUpdatedLocked 0 ");

                        notifyInputUpdatedLocked(userState, inputId);

                        break;

                    }

                }

            }

        }

        for (String inputId : userState.inputMap.keySet()) {

            if (!inputMap.containsKey(inputId)) {

                TvInputInfo info = userState.inputMap.get(inputId).info;

                ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());

                if (serviceState != null) {

                    abortPendingCreateSessionRequestsLocked(serviceState, inputId, userId);

                }

                Slog.e(TAG, "notifyInputRemovedLocked 1 ");

                notifyInputRemovedLocked(userState, inputId);

            }

        }

        userState.inputMap.clear();

        userState.inputMap = inputMap;

    }

private void notifyInputRemovedLocked(UserState userState, String inputId) {

        if (DEBUG) {

            Slog.d(TAG, "notifyInputRemovedLocked(inputId=" + inputId + ")");

        }

        for (ITvInputManagerCallback callback : userState.callbackSet) {

            try {

                callback.onInputRemoved(inputId);

            } catch (RemoteException e) {

                Slog.e(TAG, "failed to report removed input to callback", e);

            }

        }

    }

七, app层注册callback

 private TvInputManager.TvInputCallback callback = new TvInputManager.TvInputCallback() {

        @Override

        public void onInputStateChanged(String inputId, int state) {

            super.onInputStateChanged(inputId, state);

        }

        @Override

        public void onInputAdded(String inputId) {

            super.onInputAdded(inputId);

            L.d(TAG, "onInputAdded inputId=" + inputId);

            TvInputInfo inputAdded = mTvInputManager.getTvInputInfo(inputId);

            if (inputAdded != null && (mInputDevices.size() == 0 || mInputDevices.size() > 0 && !mInputDevices.contains(inputAdded))) {

                mInputDevices.add(inputAdded);

            }

            L.d(TAG, "onInputAdded mInputDevices.size=" + mInputDevices.size());

            invalidDeviceState(true);

        }

        @Override

        public void onInputRemoved(String inputId) {

            super.onInputRemoved(inputId);

            L.d(TAG, "onInputRemoved inputId=" + inputId);

            TvInputInfo inputInfo;

            Iterator<TvInputInfo> iterator = mInputDevices.iterator();

            while (iterator.hasNext()) {

                inputInfo = iterator.next();

                if (inputInfo.getId().equals(inputId)) {

                    iterator.remove();

                }

            }

            L.d(TAG, "onInputRemoved mInputDevices.size=" + mInputDevices.size());

            invalidDeviceState(true);

        }

    };

继续阅读