WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
{
 /* ! */

 dec_struct_t * ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);

    WORD32 i4_err_status = 0;
    UWORD8 *pu1_buf = NULL;
    WORD32 buflen;
    UWORD32 u4_max_ofst, u4_length_of_start_code = 0;

    UWORD32 bytes_consumed = 0;
    UWORD32 cur_slice_is_nonref = 0;
    UWORD32 u4_next_is_aud;
    UWORD32 u4_first_start_code_found = 0;
    WORD32 ret = 0,api_ret_value = IV_SUCCESS;
    WORD32 header_data_left = 0,frame_data_left = 0;
    UWORD8 *pu1_bitstrm_buf;
 ivd_video_decode_ip_t *ps_dec_ip;
 ivd_video_decode_op_t *ps_dec_op;

    ithread_set_name((void*)"Parse_thread");

    ps_dec_ip = (ivd_video_decode_ip_t *)pv_api_ip;
    ps_dec_op = (ivd_video_decode_op_t *)pv_api_op;

 {
        UWORD32 u4_size;
        u4_size = ps_dec_op->u4_size;
        memset(ps_dec_op, 0, sizeof(ivd_video_decode_op_t));
        ps_dec_op->u4_size = u4_size;
 }

    ps_dec->pv_dec_out = ps_dec_op;
 if(ps_dec->init_done != 1)
 {
 return IV_FAIL;
 }

 /*Data memory barries instruction,so that bitstream write by the application is complete*/
    DATA_SYNC();

 if(0 == ps_dec->u1_flushfrm)
 {
 if(ps_dec_ip->pv_stream_buffer == NULL)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DEC_FRM_BS_BUF_NULL;
 return IV_FAIL;
 }
 if(ps_dec_ip->u4_num_Bytes <= 0)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DEC_NUMBYTES_INV;
 return IV_FAIL;

 }
 }
    ps_dec->u1_pic_decode_done = 0;

    ps_dec_op->u4_num_bytes_consumed = 0;

    ps_dec->ps_out_buffer = NULL;

 if(ps_dec_ip->u4_size
 >= offsetof(ivd_video_decode_ip_t, s_out_buffer))
        ps_dec->ps_out_buffer = &ps_dec_ip->s_out_buffer;

    ps_dec->u4_fmt_conv_cur_row = 0;

    ps_dec->u4_output_present = 0;
    ps_dec->s_disp_op.u4_error_code = 1;
    ps_dec->u4_fmt_conv_num_rows = FMT_CONV_NUM_ROWS;
 if(0 == ps_dec->u4_share_disp_buf
 && ps_dec->i4_decode_header == 0)
 {
        UWORD32 i;
 if(ps_dec->ps_out_buffer->u4_num_bufs == 0)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
 return IV_FAIL;
 }

 for(i = 0; i < ps_dec->ps_out_buffer->u4_num_bufs; i++)
 {
 if(ps_dec->ps_out_buffer->pu1_bufs[i] == NULL)
 {
                ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                ps_dec_op->u4_error_code |= IVD_DISP_FRM_OP_BUF_NULL;
 return IV_FAIL;
 }

 if(ps_dec->ps_out_buffer->u4_min_out_buf_size[i] == 0)
 {
                ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                ps_dec_op->u4_error_code |=
                                IVD_DISP_FRM_ZERO_OP_BUF_SIZE;
 return IV_FAIL;
 }
 }
 }

 if(ps_dec->u4_total_frames_decoded >= NUM_FRAMES_LIMIT)
 {
        ps_dec_op->u4_error_code = ERROR_FRAME_LIMIT_OVER;
 return IV_FAIL;
 }

 /* ! */
    ps_dec->u4_ts = ps_dec_ip->u4_ts;

    ps_dec_op->u4_error_code = 0;
    ps_dec_op->e_pic_type = -1;
    ps_dec_op->u4_output_present = 0;
    ps_dec_op->u4_frame_decoded_flag = 0;

    ps_dec->i4_frametype = -1;
    ps_dec->i4_content_type = -1;
 /*
     * For field pictures, set the bottom and top picture decoded u4_flag correctly.
     */
 {
 if((TOP_FIELD_ONLY | BOT_FIELD_ONLY) == ps_dec->u1_top_bottom_decoded)
 {
            ps_dec->u1_top_bottom_decoded = 0;
 }
 }
    ps_dec->u4_slice_start_code_found = 0;

 /* In case the deocder is not in flush mode(in shared mode),
     then decoder has to pick up a buffer to write current frame.
     Check if a frame is available in such cases */

 if(ps_dec->u1_init_dec_flag == 1 && ps_dec->u4_share_disp_buf == 1
 && ps_dec->u1_flushfrm == 0)
 {
        UWORD32 i;

        WORD32 disp_avail = 0, free_id;

 /* Check if at least one buffer is available with the codec */
 /* If not then return to application with error */
 for(i = 0; i < ps_dec->u1_pic_bufs; i++)
 {
 if(0 == ps_dec->u4_disp_buf_mapping[i]
 || 1 == ps_dec->u4_disp_buf_to_be_freed[i])
 {
                disp_avail = 1;
 break;
 }

 }

 if(0 == disp_avail)
 {
 /* If something is queued for display wait for that buffer to be returned */

            ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;
            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
 return (IV_FAIL);
 }

 while(1)
 {
 pic_buffer_t *ps_pic_buf;
            ps_pic_buf = (pic_buffer_t *)ih264_buf_mgr_get_next_free(
 (buf_mgr_t *)ps_dec->pv_pic_buf_mgr, &free_id);

 if(ps_pic_buf == NULL)
 {
                UWORD32 i, display_queued = 0;

 /* check if any buffer was given for display which is not returned yet */
 for(i = 0; i < (MAX_DISP_BUFS_NEW); i++)
 {
 if(0 != ps_dec->u4_disp_buf_mapping[i])
 {
                        display_queued = 1;
 break;
 }
 }
 /* If some buffer is queued for display, then codec has to singal an error and wait
                 for that buffer to be returned.
                 If nothing is queued for display then codec has ownership of all display buffers
                 and it can reuse any of the existing buffers and continue decoding */

 if(1 == display_queued)
 {
 /* If something is queued for display wait for that buffer to be returned */
                    ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;
                    ps_dec_op->u4_error_code |= (1
 << IVD_UNSUPPORTEDPARAM);
 return (IV_FAIL);
 }
 }
 else
 {
 /* If the buffer is with display, then mark it as in use and then look for a buffer again */
 if(1 == ps_dec->u4_disp_buf_mapping[free_id])
 {
                    ih264_buf_mgr_set_status(
 (buf_mgr_t *)ps_dec->pv_pic_buf_mgr,
                                    free_id,
                                    BUF_MGR_IO);
 }
 else
 {
 /**
                     *  Found a free buffer for present call. Release it now.
                     *  Will be again obtained later.
                     */
                    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,
                                          free_id,
                                          BUF_MGR_IO);
 break;
 }
 }
 }

 }

 if(ps_dec->u1_flushfrm && ps_dec->u1_init_dec_flag)
 {

        ih264d_get_next_display_field(ps_dec, ps_dec->ps_out_buffer,
 &(ps_dec->s_disp_op));
 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
            ps_dec->u4_fmt_conv_cur_row = 0;
            ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht;
            ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
                                  ps_dec->u4_fmt_conv_cur_row,
                                  ps_dec->u4_fmt_conv_num_rows);
            ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;
            ps_dec->u4_output_present = 1;

 }
        ih264d_release_display_field(ps_dec, &(ps_dec->s_disp_op));

        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;
        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;

        ps_dec_op->u4_new_seq = 0;

        ps_dec_op->u4_output_present = ps_dec->u4_output_present;
        ps_dec_op->u4_progressive_frame_flag =
                        ps_dec->s_disp_op.u4_progressive_frame_flag;
        ps_dec_op->e_output_format =
                        ps_dec->s_disp_op.e_output_format;
        ps_dec_op->s_disp_frm_buf = ps_dec->s_disp_op.s_disp_frm_buf;
        ps_dec_op->e4_fld_type = ps_dec->s_disp_op.e4_fld_type;
        ps_dec_op->u4_ts = ps_dec->s_disp_op.u4_ts;
        ps_dec_op->u4_disp_buf_id = ps_dec->s_disp_op.u4_disp_buf_id;

 /*In the case of flush ,since no frame is decoded set pic type as invalid*/
        ps_dec_op->u4_is_ref_flag = -1;
        ps_dec_op->e_pic_type = IV_NA_FRAME;
        ps_dec_op->u4_frame_decoded_flag = 0;

 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
 return (IV_SUCCESS);
 }
 else
 return (IV_FAIL);

 }
 if(ps_dec->u1_res_changed == 1)
 {
 /*if resolution has changed and all buffers have been flushed, reset decoder*/
        ih264d_init_decoder(ps_dec);
 }

    ps_dec->u4_prev_nal_skipped = 0;

    ps_dec->u2_cur_mb_addr = 0;
    ps_dec->u2_total_mbs_coded = 0;
    ps_dec->u2_cur_slice_num = 0;
    ps_dec->cur_dec_mb_num = 0;
    ps_dec->cur_recon_mb_num = 0;
    ps_dec->u4_first_slice_in_pic = 2;
    ps_dec->u1_first_pb_nal_in_pic = 1;
    ps_dec->u1_slice_header_done = 0;
    ps_dec->u1_dangling_field = 0;

    ps_dec->u4_dec_thread_created = 0;
    ps_dec->u4_bs_deblk_thread_created = 0;
    ps_dec->u4_cur_bs_mb_num = 0;
    ps_dec->u4_start_recon_deblk  = 0;

    DEBUG_THREADS_PRINTF(" Starting process call\n");

    ps_dec->u4_pic_buf_got = 0;

 do
 {
        WORD32 buf_size;

        pu1_buf = (UWORD8*)ps_dec_ip->pv_stream_buffer
 + ps_dec_op->u4_num_bytes_consumed;

        u4_max_ofst = ps_dec_ip->u4_num_Bytes
 - ps_dec_op->u4_num_bytes_consumed;

 /* If dynamic bitstream buffer is not allocated and
         * header decode is done, then allocate dynamic bitstream buffer
         */
 if((NULL == ps_dec->pu1_bits_buf_dynamic) &&
 (ps_dec->i4_header_decoded & 1))
 {
            WORD32 size;

 void *pv_buf;
 void *pv_mem_ctxt = ps_dec->pv_mem_ctxt;
            size = MAX(256000, ps_dec->u2_pic_wd * ps_dec->u2_pic_ht * 3 / 2);
            pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
            RETURN_IF((NULL == pv_buf), IV_FAIL);
            ps_dec->pu1_bits_buf_dynamic = pv_buf;
            ps_dec->u4_dynamic_bits_buf_size = size;
 }

 if(ps_dec->pu1_bits_buf_dynamic)
 {
            pu1_bitstrm_buf = ps_dec->pu1_bits_buf_dynamic;
            buf_size = ps_dec->u4_dynamic_bits_buf_size;
 }
 else
 {
            pu1_bitstrm_buf = ps_dec->pu1_bits_buf_static;
            buf_size = ps_dec->u4_static_bits_buf_size;
 }

        u4_next_is_aud = 0;

        buflen = ih264d_find_start_code(pu1_buf, 0, u4_max_ofst,
 &u4_length_of_start_code,
 &u4_next_is_aud);

         if(buflen == -1)
             buflen = 0;
         /* Ignore bytes beyond the allocated size of intermediate buffer */
        /* Since 8 bytes are read ahead, ensure 8 bytes are free at the
        end of the buffer, which will be memset to 0 after emulation prevention */
        buflen = MIN(buflen, buf_size - 8);

         bytes_consumed = buflen + u4_length_of_start_code;
         ps_dec_op->u4_num_bytes_consumed += bytes_consumed;

 {
            UWORD8 u1_firstbyte, u1_nal_ref_idc;

 if(ps_dec->i4_app_skip_mode == IVD_SKIP_B)
 {
                u1_firstbyte = *(pu1_buf + u4_length_of_start_code);
                u1_nal_ref_idc = (UWORD8)(NAL_REF_IDC(u1_firstbyte));
 if(u1_nal_ref_idc == 0)
 {
 /*skip non reference frames*/
                    cur_slice_is_nonref = 1;
 continue;
 }
 else
 {
 if(1 == cur_slice_is_nonref)
 {
 /*We have encountered a referenced frame,return to app*/
                        ps_dec_op->u4_num_bytes_consumed -=
                                        bytes_consumed;
                        ps_dec_op->e_pic_type = IV_B_FRAME;
                        ps_dec_op->u4_error_code =
                                        IVD_DEC_FRM_SKIPPED;
                        ps_dec_op->u4_error_code |= (1
 << IVD_UNSUPPORTEDPARAM);
                        ps_dec_op->u4_frame_decoded_flag = 0;
                        ps_dec_op->u4_size =
 sizeof(ivd_video_decode_op_t);
 /*signal the decode thread*/
                        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
                            ih264d_signal_bs_deblk_thread(ps_dec);
 }

 return (IV_FAIL);
 }
 }

 }

 }

 if(buflen)
 {
            memcpy(pu1_bitstrm_buf, pu1_buf + u4_length_of_start_code,
                   buflen);
 /* Decoder may read extra 8 bytes near end of the frame */
 if((buflen + 8) < buf_size)
 {
                memset(pu1_bitstrm_buf + buflen, 0, 8);
 }
            u4_first_start_code_found = 1;

 }
 else
 {
 /*start code not found*/

 if(u4_first_start_code_found == 0)
 {
 /*no start codes found in current process call*/

                ps_dec->i4_error_code = ERROR_START_CODE_NOT_FOUND;
                ps_dec_op->u4_error_code |= 1 << IVD_INSUFFICIENTDATA;

 if(ps_dec->u4_pic_buf_got == 0)
 {

                    ih264d_fill_output_struct_from_context(ps_dec,
                                                           ps_dec_op);

                    ps_dec_op->u4_error_code = ps_dec->i4_error_code;
                    ps_dec_op->u4_frame_decoded_flag = 0;

 return (IV_FAIL);
 }
 else
 {
                    ps_dec->u1_pic_decode_done = 1;
 continue;
 }
 }
 else
 {
 /* a start code has already been found earlier in the same process call*/
                frame_data_left = 0;
                header_data_left = 0;
 continue;
 }

 }

        ps_dec->u4_return_to_app = 0;
        ret = ih264d_parse_nal_unit(dec_hdl, ps_dec_op,
                              pu1_bitstrm_buf, buflen);
 if(ret != OK)
 {
            UWORD32 error =  ih264d_map_error(ret);
            ps_dec_op->u4_error_code = error | ret;
            api_ret_value = IV_FAIL;

 if((ret == IVD_RES_CHANGED)
 || (ret == IVD_MEM_ALLOC_FAILED)
 || (ret == ERROR_UNAVAIL_PICBUF_T)
 || (ret == ERROR_UNAVAIL_MVBUF_T)
 || (ret == ERROR_INV_SPS_PPS_T))
 {
                ps_dec->u4_slice_start_code_found = 0;
 break;
 }

 if((ret == ERROR_INCOMPLETE_FRAME) || (ret == ERROR_DANGLING_FIELD_IN_PIC))
 {
                ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
                api_ret_value = IV_FAIL;
 break;
 }

 if(ret == ERROR_IN_LAST_SLICE_OF_PIC)
 {
                api_ret_value = IV_FAIL;
 break;
 }

 }

 if(ps_dec->u4_return_to_app)
 {
 /*We have encountered a referenced frame,return to app*/
            ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
            ps_dec_op->u4_error_code = IVD_DEC_FRM_SKIPPED;
            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
            ps_dec_op->u4_frame_decoded_flag = 0;
            ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
 /*signal the decode thread*/
            ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
                ih264d_signal_bs_deblk_thread(ps_dec);
 }
 return (IV_FAIL);

 }

        header_data_left = ((ps_dec->i4_decode_header == 1)
 && (ps_dec->i4_header_decoded != 3)
 && (ps_dec_op->u4_num_bytes_consumed
 < ps_dec_ip->u4_num_Bytes));
        frame_data_left = (((ps_dec->i4_decode_header == 0)
 && ((ps_dec->u1_pic_decode_done == 0)
 || (u4_next_is_aud == 1)))
 && (ps_dec_op->u4_num_bytes_consumed
 < ps_dec_ip->u4_num_Bytes));
 }
 while(( header_data_left == 1)||(frame_data_left == 1));

 if((ps_dec->u4_slice_start_code_found == 1)
 && (ret != IVD_MEM_ALLOC_FAILED)
 && ps_dec->u2_total_mbs_coded < ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
 {
        WORD32 num_mb_skipped;
        WORD32 prev_slice_err;
 pocstruct_t temp_poc;
        WORD32 ret1;
        WORD32 ht_in_mbs;
        ht_in_mbs = ps_dec->u2_pic_ht >> (4 + ps_dec->ps_cur_slice->u1_field_pic_flag);
        num_mb_skipped = (ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
 - ps_dec->u2_total_mbs_coded;

 if(ps_dec->u4_first_slice_in_pic && (ps_dec->u4_pic_buf_got == 0))
            prev_slice_err = 1;
 else
            prev_slice_err = 2;

 if(ps_dec->u4_first_slice_in_pic && (ps_dec->u2_total_mbs_coded == 0))
            prev_slice_err = 1;

        ret1 = ih264d_mark_err_slice_skip(ps_dec, num_mb_skipped, ps_dec->u1_nal_unit_type == IDR_SLICE_NAL, ps_dec->ps_cur_slice->u2_frame_num,
 &temp_poc, prev_slice_err);

 if((ret1 == ERROR_UNAVAIL_PICBUF_T) || (ret1 == ERROR_UNAVAIL_MVBUF_T) ||
 (ret1 == ERROR_INV_SPS_PPS_T))
 {
            ret = ret1;
 }
 }

 if((ret == IVD_RES_CHANGED)
 || (ret == IVD_MEM_ALLOC_FAILED)
 || (ret == ERROR_UNAVAIL_PICBUF_T)
 || (ret == ERROR_UNAVAIL_MVBUF_T)
 || (ret == ERROR_INV_SPS_PPS_T))
 {

 /* signal the decode thread */
        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet */
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 /* dont consume bitstream for change in resolution case */
 if(ret == IVD_RES_CHANGED)
 {
            ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
 }
 return IV_FAIL;
 }

 if(ps_dec->u1_separate_parse)
 {
 /* If Format conversion is not complete,
         complete it here */
 if(ps_dec->u4_num_cores == 2)
 {

 /*do deblocking of all mbs*/
 if((ps_dec->u4_nmb_deblk == 0) &&(ps_dec->u4_start_recon_deblk == 1) && (ps_dec->ps_cur_sps->u1_mb_aff_flag == 0))
 {
                UWORD32 u4_num_mbs,u4_max_addr;
 tfr_ctxt_t s_tfr_ctxt;
 tfr_ctxt_t *ps_tfr_cxt = &s_tfr_ctxt;
 pad_mgr_t *ps_pad_mgr = &ps_dec->s_pad_mgr;

 /*BS is done for all mbs while parsing*/
                u4_max_addr = (ps_dec->u2_frm_wd_in_mbs * ps_dec->u2_frm_ht_in_mbs) - 1;
                ps_dec->u4_cur_bs_mb_num = u4_max_addr + 1;

                ih264d_init_deblk_tfr_ctxt(ps_dec, ps_pad_mgr, ps_tfr_cxt,
                                           ps_dec->u2_frm_wd_in_mbs, 0);

                u4_num_mbs = u4_max_addr
 - ps_dec->u4_cur_deblk_mb_num + 1;

                DEBUG_PERF_PRINTF("mbs left for deblocking= %d \n",u4_num_mbs);

 if(u4_num_mbs != 0)
                    ih264d_check_mb_map_deblk(ps_dec, u4_num_mbs,
                                                   ps_tfr_cxt,1);

                ps_dec->u4_start_recon_deblk  = 0;

 }

 }

 /*signal the decode thread*/
        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 }

    DATA_SYNC();

 if((ps_dec_op->u4_error_code & 0xff)
 != ERROR_DYNAMIC_RESOLUTION_NOT_SUPPORTED)
 {
        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;
        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;
 }

 if(ps_dec->i4_header_decoded != 3)
 {
        ps_dec_op->u4_error_code |= (1 << IVD_INSUFFICIENTDATA);

 }

 if(ps_dec->i4_decode_header == 1 && ps_dec->i4_header_decoded != 3)
 {
        ps_dec_op->u4_error_code |= (1 << IVD_INSUFFICIENTDATA);

 }
 if(ps_dec->u4_prev_nal_skipped)
 {
 /*We have encountered a referenced frame,return to app*/
        ps_dec_op->u4_error_code = IVD_DEC_FRM_SKIPPED;
        ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
        ps_dec_op->u4_frame_decoded_flag = 0;
        ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 return (IV_FAIL);

 }

 if((ps_dec->u4_slice_start_code_found == 1)
 && (ERROR_DANGLING_FIELD_IN_PIC != i4_err_status))
 {
 /*
         * For field pictures, set the bottom and top picture decoded u4_flag correctly.
         */

 if(ps_dec->ps_cur_slice->u1_field_pic_flag)
 {
 if(1 == ps_dec->ps_cur_slice->u1_bottom_field_flag)
 {
                ps_dec->u1_top_bottom_decoded |= BOT_FIELD_ONLY;
 }
 else
 {
                ps_dec->u1_top_bottom_decoded |= TOP_FIELD_ONLY;
 }
 }

 /* if new frame in not found (if we are still getting slices from previous frame)
         * ih264d_deblock_display is not called. Such frames will not be added to reference /display
         */
 if (((ps_dec->ps_dec_err_status->u1_err_flag & REJECT_CUR_PIC) == 0)
 && (ps_dec->u4_pic_buf_got == 1))
 {
 /* Calling Function to deblock Picture and Display */
            ret = ih264d_deblock_display(ps_dec);
 if(ret != 0)
 {
 return IV_FAIL;
 }
 }

 /*set to complete ,as we dont support partial frame decode*/
 if(ps_dec->i4_header_decoded == 3)
 {
            ps_dec->u2_total_mbs_coded = ps_dec->ps_cur_sps->u2_max_mb_addr + 1;
 }

 /*Update the i4_frametype at the end of picture*/
 if(ps_dec->ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL)
 {
            ps_dec->i4_frametype = IV_IDR_FRAME;
 }
 else if(ps_dec->i4_pic_type == B_SLICE)
 {
            ps_dec->i4_frametype = IV_B_FRAME;
 }
 else if(ps_dec->i4_pic_type == P_SLICE)
 {
            ps_dec->i4_frametype = IV_P_FRAME;
 }
 else if(ps_dec->i4_pic_type == I_SLICE)
 {
            ps_dec->i4_frametype = IV_I_FRAME;
 }
 else
 {
            H264_DEC_DEBUG_PRINT("Shouldn't come here\n");
 }

        ps_dec->i4_content_type = ps_dec->ps_cur_slice->u1_field_pic_flag;

        ps_dec->u4_total_frames_decoded = ps_dec->u4_total_frames_decoded + 2;
        ps_dec->u4_total_frames_decoded = ps_dec->u4_total_frames_decoded
 - ps_dec->ps_cur_slice->u1_field_pic_flag;

 }

 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
        ih264d_signal_bs_deblk_thread(ps_dec);
 }

 {
 /* In case the decoder is configured to run in low delay mode,
         * then get display buffer and then format convert.
         * Note in this mode, format conversion does not run paralelly in a thread and adds to the codec cycles
         */

 if((IVD_DECODE_FRAME_OUT == ps_dec->e_frm_out_mode)
 && ps_dec->u1_init_dec_flag)
 {

            ih264d_get_next_display_field(ps_dec, ps_dec->ps_out_buffer,
 &(ps_dec->s_disp_op));
 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
                ps_dec->u4_fmt_conv_cur_row = 0;
                ps_dec->u4_output_present = 1;
 }
 }

        ih264d_fill_output_struct_from_context(ps_dec, ps_dec_op);

 /* If Format conversion is not complete,
         complete it here */
 if(ps_dec->u4_output_present &&
 (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))
 {
            ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht
 - ps_dec->u4_fmt_conv_cur_row;
            ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
                                  ps_dec->u4_fmt_conv_cur_row,
                                  ps_dec->u4_fmt_conv_num_rows);
            ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;
 }

        ih264d_release_display_field(ps_dec, &(ps_dec->s_disp_op));
 }

 if(ps_dec->i4_decode_header == 1 && (ps_dec->i4_header_decoded & 1) == 1)
 {
        ps_dec_op->u4_progressive_frame_flag = 1;
 if((NULL != ps_dec->ps_cur_sps) && (1 == (ps_dec->ps_cur_sps->u1_is_valid)))
 {
 if((0 == ps_dec->ps_sps->u1_frame_mbs_only_flag)
 && (0 == ps_dec->ps_sps->u1_mb_aff_flag))
                ps_dec_op->u4_progressive_frame_flag = 0;

 }
 }

 /*Data memory barrier instruction,so that yuv write by the library is complete*/
    DATA_SYNC();

    H264_DEC_DEBUG_PRINT("The num bytes consumed: %d\n",
                         ps_dec_op->u4_num_bytes_consumed);
 return api_ret_value;
}


static EAS_RESULT PushcdlStack (EAS_U32 *pStack, EAS_INT *pStackPtr, EAS_U32 value)

 {

     /* stack overflow, return an error */
    if (*pStackPtr >= CDL_STACK_SIZE)
         return EAS_ERROR_FILE_FORMAT;

     /* push the value onto the stack */
     *pStackPtr = *pStackPtr + 1;
    pStack[*pStackPtr] = value;
 return EAS_SUCCESS;
}

A remote code execution vulnerability in sonivox in Mediaserver could enable an attacker using a specially crafted file to cause memory corruption during media file and data processing. This issue is rated as Critical due to the possibility of remote code execution within the context of the Mediaserver process. Product: Android. Versions: 4.4.4, 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1.1. Android ID: A-34031018.


static EAS_RESULT PushcdlStack (EAS_U32 *pStack, EAS_INT *pStackPtr, EAS_U32 value)

 {

     /* stack overflow, return an error */
    if (*pStackPtr >= (CDL_STACK_SIZE - 1)) {
        ALOGE("b/34031018, stackPtr(%d)", *pStackPtr);
        android_errorWriteLog(0x534e4554, "34031018");
         return EAS_ERROR_FILE_FORMAT;
    }

     /* push the value onto the stack */
     *pStackPtr = *pStackPtr + 1;
    pStack[*pStackPtr] = value;
 return EAS_SUCCESS;
}


IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
{
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    WORD32 value;

    WORD32 i;
    WORD32 vps_id;
    WORD32 sps_max_sub_layers;
    WORD32 sps_id;
    WORD32 sps_temporal_id_nesting_flag;
 sps_t *ps_sps;
 profile_tier_lvl_info_t s_ptl;
 bitstrm_t *ps_bitstrm = &ps_codec->s_parse.s_bitstrm;

    BITS_PARSE("video_parameter_set_id", value, ps_bitstrm, 4);
    vps_id = value;
    vps_id = CLIP3(vps_id, 0, MAX_VPS_CNT - 1);

    BITS_PARSE("sps_max_sub_layers_minus1", value, ps_bitstrm, 3);
    sps_max_sub_layers = value + 1;
    sps_max_sub_layers = CLIP3(sps_max_sub_layers, 1, 7);

    BITS_PARSE("sps_temporal_id_nesting_flag", value, ps_bitstrm, 1);
    sps_temporal_id_nesting_flag = value;

    ret = ihevcd_profile_tier_level(ps_bitstrm, &(s_ptl), 1,
 (sps_max_sub_layers - 1));

    UEV_PARSE("seq_parameter_set_id", value, ps_bitstrm);
    sps_id = value;

 if((sps_id >= MAX_SPS_CNT) || (sps_id < 0))
 {
 if(ps_codec->i4_sps_done)
 return IHEVCD_UNSUPPORTED_SPS_ID;
 else
            sps_id = 0;
 }

    ps_sps = (ps_codec->s_parse.ps_sps_base + MAX_SPS_CNT - 1);
    ps_sps->i1_sps_id = sps_id;
    ps_sps->i1_vps_id = vps_id;
    ps_sps->i1_sps_max_sub_layers = sps_max_sub_layers;
    ps_sps->i1_sps_temporal_id_nesting_flag = sps_temporal_id_nesting_flag;
 /* This is used only during initialization to get reorder count etc */
    ps_codec->i4_sps_id = sps_id;
    memcpy(&ps_sps->s_ptl, &s_ptl, sizeof(profile_tier_lvl_info_t));

    UEV_PARSE("chroma_format_idc", value, ps_bitstrm);
    ps_sps->i1_chroma_format_idc = value;

 if(ps_sps->i1_chroma_format_idc != CHROMA_FMT_IDC_YUV420)
 {
        ps_codec->s_parse.i4_error_code = IHEVCD_UNSUPPORTED_CHROMA_FMT_IDC;
 return (IHEVCD_ERROR_T)IHEVCD_UNSUPPORTED_CHROMA_FMT_IDC;
 }

 if(CHROMA_FMT_IDC_YUV444_PLANES == ps_sps->i1_chroma_format_idc)
 {
        BITS_PARSE("separate_colour_plane_flag", value, ps_bitstrm, 1);
        ps_sps->i1_separate_colour_plane_flag = value;
 }
 else
 {
        ps_sps->i1_separate_colour_plane_flag = 0;
 }

    UEV_PARSE("pic_width_in_luma_samples", value, ps_bitstrm);
    ps_sps->i2_pic_width_in_luma_samples = value;

    UEV_PARSE("pic_height_in_luma_samples", value, ps_bitstrm);
    ps_sps->i2_pic_height_in_luma_samples = value;

 if((0 >= ps_sps->i2_pic_width_in_luma_samples) || (0 >= ps_sps->i2_pic_height_in_luma_samples))
 return IHEVCD_INVALID_PARAMETER;

 /* i2_pic_width_in_luma_samples and i2_pic_height_in_luma_samples
       should be multiples of min_cb_size. Here these are aligned to 8,
       i.e. smallest CB size */
    ps_sps->i2_pic_width_in_luma_samples = ALIGN8(ps_sps->i2_pic_width_in_luma_samples);
    ps_sps->i2_pic_height_in_luma_samples = ALIGN8(ps_sps->i2_pic_height_in_luma_samples);

 if((ps_sps->i2_pic_width_in_luma_samples > ps_codec->i4_max_wd) ||
 (ps_sps->i2_pic_width_in_luma_samples * ps_sps->i2_pic_height_in_luma_samples >
                       ps_codec->i4_max_wd * ps_codec->i4_max_ht) ||
 (ps_sps->i2_pic_height_in_luma_samples > MAX(ps_codec->i4_max_wd, ps_codec->i4_max_ht)))
 {
        ps_codec->i4_new_max_wd = ps_sps->i2_pic_width_in_luma_samples;
        ps_codec->i4_new_max_ht = ps_sps->i2_pic_height_in_luma_samples;
 return (IHEVCD_ERROR_T)IHEVCD_UNSUPPORTED_DIMENSIONS;
 }

    BITS_PARSE("pic_cropping_flag", value, ps_bitstrm, 1);
    ps_sps->i1_pic_cropping_flag = value;

 if(ps_sps->i1_pic_cropping_flag)
 {

        UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
        ps_sps->i2_pic_crop_left_offset = value;

        UEV_PARSE("pic_crop_right_offset", value, ps_bitstrm);
        ps_sps->i2_pic_crop_right_offset = value;

        UEV_PARSE("pic_crop_top_offset", value, ps_bitstrm);
        ps_sps->i2_pic_crop_top_offset = value;

        UEV_PARSE("pic_crop_bottom_offset", value, ps_bitstrm);
        ps_sps->i2_pic_crop_bottom_offset = value;
 }
 else
 {
        ps_sps->i2_pic_crop_left_offset = 0;
        ps_sps->i2_pic_crop_right_offset = 0;
        ps_sps->i2_pic_crop_top_offset = 0;
        ps_sps->i2_pic_crop_bottom_offset = 0;
 }

    UEV_PARSE("bit_depth_luma_minus8", value, ps_bitstrm);
 if(0 != value)
 return IHEVCD_UNSUPPORTED_BIT_DEPTH;

    UEV_PARSE("bit_depth_chroma_minus8", value, ps_bitstrm);
 if(0 != value)
 return IHEVCD_UNSUPPORTED_BIT_DEPTH;

    UEV_PARSE("log2_max_pic_order_cnt_lsb_minus4", value, ps_bitstrm);
    ps_sps->i1_log2_max_pic_order_cnt_lsb = value + 4;

    BITS_PARSE("sps_sub_layer_ordering_info_present_flag", value, ps_bitstrm, 1);
    ps_sps->i1_sps_sub_layer_ordering_info_present_flag = value;

    i = (ps_sps->i1_sps_sub_layer_ordering_info_present_flag ? 0 : (ps_sps->i1_sps_max_sub_layers - 1));
 for(; i < ps_sps->i1_sps_max_sub_layers; i++)
 {

         UEV_PARSE("max_dec_pic_buffering", value, ps_bitstrm);
         ps_sps->ai1_sps_max_dec_pic_buffering[i] = value + 1;

         UEV_PARSE("num_reorder_pics", value, ps_bitstrm);
         ps_sps->ai1_sps_max_num_reorder_pics[i] = value;

         UEV_PARSE("max_latency_increase", value, ps_bitstrm);
         ps_sps->ai1_sps_max_latency_increase[i] = value;
     }
    UEV_PARSE("log2_min_coding_block_size_minus3", value, ps_bitstrm);
    ps_sps->i1_log2_min_coding_block_size = value + 3;

    UEV_PARSE("log2_diff_max_min_coding_block_size", value, ps_bitstrm);
    ps_sps->i1_log2_diff_max_min_coding_block_size = value;

    UEV_PARSE("log2_min_transform_block_size_minus2", value, ps_bitstrm);
    ps_sps->i1_log2_min_transform_block_size = value + 2;

    UEV_PARSE("log2_diff_max_min_transform_block_size", value, ps_bitstrm);
    ps_sps->i1_log2_diff_max_min_transform_block_size = value;

    ps_sps->i1_log2_max_transform_block_size = ps_sps->i1_log2_min_transform_block_size +
                    ps_sps->i1_log2_diff_max_min_transform_block_size;

    ps_sps->i1_log2_ctb_size = ps_sps->i1_log2_min_coding_block_size +
                    ps_sps->i1_log2_diff_max_min_coding_block_size;

 if((ps_sps->i1_log2_min_coding_block_size < 3) ||
 (ps_sps->i1_log2_min_transform_block_size < 2) ||
 (ps_sps->i1_log2_diff_max_min_transform_block_size < 0) ||
 (ps_sps->i1_log2_max_transform_block_size > ps_sps->i1_log2_ctb_size) ||
 (ps_sps->i1_log2_ctb_size < 4) ||
 (ps_sps->i1_log2_ctb_size > 6))
 {
 return IHEVCD_INVALID_PARAMETER;
 }

    ps_sps->i1_log2_min_pcm_coding_block_size = 0;
    ps_sps->i1_log2_diff_max_min_pcm_coding_block_size = 0;

    UEV_PARSE("max_transform_hierarchy_depth_inter", value, ps_bitstrm);
    ps_sps->i1_max_transform_hierarchy_depth_inter = value;

    UEV_PARSE("max_transform_hierarchy_depth_intra", value, ps_bitstrm);
    ps_sps->i1_max_transform_hierarchy_depth_intra = value;

 /* String has a d (enabled) in order to match with HM */
    BITS_PARSE("scaling_list_enabled_flag", value, ps_bitstrm, 1);
    ps_sps->i1_scaling_list_enable_flag = value;

 if(ps_sps->i1_scaling_list_enable_flag)
 {
        COPY_DEFAULT_SCALING_LIST(ps_sps->pi2_scaling_mat);
        BITS_PARSE("sps_scaling_list_data_present_flag", value, ps_bitstrm, 1);
        ps_sps->i1_sps_scaling_list_data_present_flag = value;

 if(ps_sps->i1_sps_scaling_list_data_present_flag)
            ihevcd_scaling_list_data(ps_codec, ps_sps->pi2_scaling_mat);
 }
 else
 {
        COPY_FLAT_SCALING_LIST(ps_sps->pi2_scaling_mat);
 }
 /* String is asymmetric_motion_partitions_enabled_flag instead of amp_enabled_flag in order to match with HM */
    BITS_PARSE("asymmetric_motion_partitions_enabled_flag", value, ps_bitstrm, 1);
    ps_sps->i1_amp_enabled_flag = value;

    BITS_PARSE("sample_adaptive_offset_enabled_flag", value, ps_bitstrm, 1);
    ps_sps->i1_sample_adaptive_offset_enabled_flag = value;

    BITS_PARSE("pcm_enabled_flag", value, ps_bitstrm, 1);
    ps_sps->i1_pcm_enabled_flag = value;

 if(ps_sps->i1_pcm_enabled_flag)
 {
        BITS_PARSE("pcm_sample_bit_depth_luma", value, ps_bitstrm, 4);
        ps_sps->i1_pcm_sample_bit_depth_luma = value + 1;

        BITS_PARSE("pcm_sample_bit_depth_chroma", value, ps_bitstrm, 4);
        ps_sps->i1_pcm_sample_bit_depth_chroma = value + 1;

        UEV_PARSE("log2_min_pcm_coding_block_size_minus3", value, ps_bitstrm);
        ps_sps->i1_log2_min_pcm_coding_block_size = value + 3;

        UEV_PARSE("log2_diff_max_min_pcm_coding_block_size", value, ps_bitstrm);
        ps_sps->i1_log2_diff_max_min_pcm_coding_block_size = value;
        BITS_PARSE("pcm_loop_filter_disable_flag", value, ps_bitstrm, 1);
        ps_sps->i1_pcm_loop_filter_disable_flag = value;

 }
    UEV_PARSE("num_short_term_ref_pic_sets", value, ps_bitstrm);
    ps_sps->i1_num_short_term_ref_pic_sets = value;

    ps_sps->i1_num_short_term_ref_pic_sets = CLIP3(ps_sps->i1_num_short_term_ref_pic_sets, 0, MAX_STREF_PICS_SPS);

 for(i = 0; i < ps_sps->i1_num_short_term_ref_pic_sets; i++)
        ihevcd_short_term_ref_pic_set(ps_bitstrm, &ps_sps->as_stref_picset[0], ps_sps->i1_num_short_term_ref_pic_sets, i, &ps_sps->as_stref_picset[i]);

    BITS_PARSE("long_term_ref_pics_present_flag", value, ps_bitstrm, 1);
    ps_sps->i1_long_term_ref_pics_present_flag = value;

 if(ps_sps->i1_long_term_ref_pics_present_flag)
 {
        UEV_PARSE("num_long_term_ref_pics_sps", value, ps_bitstrm);
        ps_sps->i1_num_long_term_ref_pics_sps = value;

 for(i = 0; i < ps_sps->i1_num_long_term_ref_pics_sps; i++)
 {
            BITS_PARSE("lt_ref_pic_poc_lsb_sps[ i ]", value, ps_bitstrm, ps_sps->i1_log2_max_pic_order_cnt_lsb);
            ps_sps->ai1_lt_ref_pic_poc_lsb_sps[i] = value;

            BITS_PARSE("used_by_curr_pic_lt_sps_flag[ i ]", value, ps_bitstrm, 1);
            ps_sps->ai1_used_by_curr_pic_lt_sps_flag[i] = value;
 }
 }

    BITS_PARSE("sps_temporal_mvp_enable_flag", value, ps_bitstrm, 1);
    ps_sps->i1_sps_temporal_mvp_enable_flag = value;

 /* Print matches HM 8-2 */
    BITS_PARSE("sps_strong_intra_smoothing_enable_flag", value, ps_bitstrm, 1);
    ps_sps->i1_strong_intra_smoothing_enable_flag = value;

    BITS_PARSE("vui_parameters_present_flag", value, ps_bitstrm, 1);
    ps_sps->i1_vui_parameters_present_flag = value;

 if(ps_sps->i1_vui_parameters_present_flag)
        ihevcd_parse_vui_parameters(ps_bitstrm,
 &ps_sps->s_vui_parameters,
                                    ps_sps->i1_sps_max_sub_layers - 1);

    BITS_PARSE("sps_extension_flag", value, ps_bitstrm, 1);

 {
        WORD32 numerator;
        WORD32 ceil_offset;

        ceil_offset = (1 << ps_sps->i1_log2_ctb_size) - 1;
        numerator = ps_sps->i2_pic_width_in_luma_samples;

        ps_sps->i2_pic_wd_in_ctb = ((numerator + ceil_offset) /
 (1 << ps_sps->i1_log2_ctb_size));

        numerator = ps_sps->i2_pic_height_in_luma_samples;
        ps_sps->i2_pic_ht_in_ctb = ((numerator + ceil_offset) /
 (1 << ps_sps->i1_log2_ctb_size));

        ps_sps->i4_pic_size_in_ctb = ps_sps->i2_pic_ht_in_ctb *
                        ps_sps->i2_pic_wd_in_ctb;

 if(0 == ps_codec->i4_sps_done)
            ps_codec->s_parse.i4_next_ctb_indx = ps_sps->i4_pic_size_in_ctb;

        numerator = ps_sps->i2_pic_width_in_luma_samples;
        ps_sps->i2_pic_wd_in_min_cb = numerator  /
 (1 << ps_sps->i1_log2_min_coding_block_size);

        numerator = ps_sps->i2_pic_height_in_luma_samples;
        ps_sps->i2_pic_ht_in_min_cb = numerator  /
 (1 << ps_sps->i1_log2_min_coding_block_size);
 }
 if((0 != ps_codec->i4_first_pic_done) &&
 ((ps_codec->i4_wd != ps_sps->i2_pic_width_in_luma_samples) ||
 (ps_codec->i4_ht != ps_sps->i2_pic_height_in_luma_samples)))
 {
        ps_codec->i4_reset_flag = 1;
        ps_codec->i4_error_code = IVD_RES_CHANGED;
 return (IHEVCD_ERROR_T)IHEVCD_FAIL;
 }

 /* Update display width and display height */
 {
        WORD32 disp_wd, disp_ht;
        WORD32 crop_unit_x, crop_unit_y;
        crop_unit_x = 1;
        crop_unit_y = 1;

 if(CHROMA_FMT_IDC_YUV420 == ps_sps->i1_chroma_format_idc)
 {
            crop_unit_x = 2;
            crop_unit_y = 2;
 }

        disp_wd = ps_sps->i2_pic_width_in_luma_samples;
        disp_wd -= ps_sps->i2_pic_crop_left_offset * crop_unit_x;
        disp_wd -= ps_sps->i2_pic_crop_right_offset * crop_unit_x;

        disp_ht = ps_sps->i2_pic_height_in_luma_samples;
        disp_ht -= ps_sps->i2_pic_crop_top_offset * crop_unit_y;
        disp_ht -= ps_sps->i2_pic_crop_bottom_offset * crop_unit_y;

 if((0 >= disp_wd) || (0 >= disp_ht))
 return IHEVCD_INVALID_PARAMETER;

        ps_codec->i4_disp_wd = disp_wd;
        ps_codec->i4_disp_ht = disp_ht;

        ps_codec->i4_wd = ps_sps->i2_pic_width_in_luma_samples;
        ps_codec->i4_ht = ps_sps->i2_pic_height_in_luma_samples;

 {
            WORD32 ref_strd;
            ref_strd = ALIGN32(ps_sps->i2_pic_width_in_luma_samples + PAD_WD);
 if(ps_codec->i4_strd < ref_strd)
 {
                ps_codec->i4_strd = ref_strd;
 }
 }

 if(0 == ps_codec->i4_share_disp_buf)
 {
 if(ps_codec->i4_disp_strd < ps_codec->i4_disp_wd)
 {
                ps_codec->i4_disp_strd = ps_codec->i4_disp_wd;
 }
 }
 else
 {
 if(ps_codec->i4_disp_strd < ps_codec->i4_strd)
 {
                ps_codec->i4_disp_strd = ps_codec->i4_strd;
 }
 }
 }

    ps_codec->i4_sps_done = 1;
 return ret;
}

A remote code execution vulnerability in libhevc in Mediaserver could enable an attacker using a specially crafted file to cause memory corruption during media file and data processing. This issue is rated as Critical due to the possibility of remote code execution within the context of the Mediaserver process. Product: Android. Versions: 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1.1. Android ID: A-33864300.


IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
{
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    WORD32 value;

    WORD32 i;
    WORD32 vps_id;
    WORD32 sps_max_sub_layers;
    WORD32 sps_id;
    WORD32 sps_temporal_id_nesting_flag;
 sps_t *ps_sps;
 profile_tier_lvl_info_t s_ptl;
 bitstrm_t *ps_bitstrm = &ps_codec->s_parse.s_bitstrm;

    BITS_PARSE("video_parameter_set_id", value, ps_bitstrm, 4);
    vps_id = value;
    vps_id = CLIP3(vps_id, 0, MAX_VPS_CNT - 1);

    BITS_PARSE("sps_max_sub_layers_minus1", value, ps_bitstrm, 3);
    sps_max_sub_layers = value + 1;
    sps_max_sub_layers = CLIP3(sps_max_sub_layers, 1, 7);

    BITS_PARSE("sps_temporal_id_nesting_flag", value, ps_bitstrm, 1);
    sps_temporal_id_nesting_flag = value;

    ret = ihevcd_profile_tier_level(ps_bitstrm, &(s_ptl), 1,
 (sps_max_sub_layers - 1));

    UEV_PARSE("seq_parameter_set_id", value, ps_bitstrm);
    sps_id = value;

 if((sps_id >= MAX_SPS_CNT) || (sps_id < 0))
 {
 if(ps_codec->i4_sps_done)
 return IHEVCD_UNSUPPORTED_SPS_ID;
 else
            sps_id = 0;
 }

    ps_sps = (ps_codec->s_parse.ps_sps_base + MAX_SPS_CNT - 1);
    ps_sps->i1_sps_id = sps_id;
    ps_sps->i1_vps_id = vps_id;
    ps_sps->i1_sps_max_sub_layers = sps_max_sub_layers;
    ps_sps->i1_sps_temporal_id_nesting_flag = sps_temporal_id_nesting_flag;
 /* This is used only during initialization to get reorder count etc */
    ps_codec->i4_sps_id = sps_id;
    memcpy(&ps_sps->s_ptl, &s_ptl, sizeof(profile_tier_lvl_info_t));

    UEV_PARSE("chroma_format_idc", value, ps_bitstrm);
    ps_sps->i1_chroma_format_idc = value;

 if(ps_sps->i1_chroma_format_idc != CHROMA_FMT_IDC_YUV420)
 {
        ps_codec->s_parse.i4_error_code = IHEVCD_UNSUPPORTED_CHROMA_FMT_IDC;
 return (IHEVCD_ERROR_T)IHEVCD_UNSUPPORTED_CHROMA_FMT_IDC;
 }

 if(CHROMA_FMT_IDC_YUV444_PLANES == ps_sps->i1_chroma_format_idc)
 {
        BITS_PARSE("separate_colour_plane_flag", value, ps_bitstrm, 1);
        ps_sps->i1_separate_colour_plane_flag = value;
 }
 else
 {
        ps_sps->i1_separate_colour_plane_flag = 0;
 }

    UEV_PARSE("pic_width_in_luma_samples", value, ps_bitstrm);
    ps_sps->i2_pic_width_in_luma_samples = value;

    UEV_PARSE("pic_height_in_luma_samples", value, ps_bitstrm);
    ps_sps->i2_pic_height_in_luma_samples = value;

 if((0 >= ps_sps->i2_pic_width_in_luma_samples) || (0 >= ps_sps->i2_pic_height_in_luma_samples))
 return IHEVCD_INVALID_PARAMETER;

 /* i2_pic_width_in_luma_samples and i2_pic_height_in_luma_samples
       should be multiples of min_cb_size. Here these are aligned to 8,
       i.e. smallest CB size */
    ps_sps->i2_pic_width_in_luma_samples = ALIGN8(ps_sps->i2_pic_width_in_luma_samples);
    ps_sps->i2_pic_height_in_luma_samples = ALIGN8(ps_sps->i2_pic_height_in_luma_samples);

 if((ps_sps->i2_pic_width_in_luma_samples > ps_codec->i4_max_wd) ||
 (ps_sps->i2_pic_width_in_luma_samples * ps_sps->i2_pic_height_in_luma_samples >
                       ps_codec->i4_max_wd * ps_codec->i4_max_ht) ||
 (ps_sps->i2_pic_height_in_luma_samples > MAX(ps_codec->i4_max_wd, ps_codec->i4_max_ht)))
 {
        ps_codec->i4_new_max_wd = ps_sps->i2_pic_width_in_luma_samples;
        ps_codec->i4_new_max_ht = ps_sps->i2_pic_height_in_luma_samples;
 return (IHEVCD_ERROR_T)IHEVCD_UNSUPPORTED_DIMENSIONS;
 }

    BITS_PARSE("pic_cropping_flag", value, ps_bitstrm, 1);
    ps_sps->i1_pic_cropping_flag = value;

 if(ps_sps->i1_pic_cropping_flag)
 {

        UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
        ps_sps->i2_pic_crop_left_offset = value;

        UEV_PARSE("pic_crop_right_offset", value, ps_bitstrm);
        ps_sps->i2_pic_crop_right_offset = value;

        UEV_PARSE("pic_crop_top_offset", value, ps_bitstrm);
        ps_sps->i2_pic_crop_top_offset = value;

        UEV_PARSE("pic_crop_bottom_offset", value, ps_bitstrm);
        ps_sps->i2_pic_crop_bottom_offset = value;
 }
 else
 {
        ps_sps->i2_pic_crop_left_offset = 0;
        ps_sps->i2_pic_crop_right_offset = 0;
        ps_sps->i2_pic_crop_top_offset = 0;
        ps_sps->i2_pic_crop_bottom_offset = 0;
 }

    UEV_PARSE("bit_depth_luma_minus8", value, ps_bitstrm);
 if(0 != value)
 return IHEVCD_UNSUPPORTED_BIT_DEPTH;

    UEV_PARSE("bit_depth_chroma_minus8", value, ps_bitstrm);
 if(0 != value)
 return IHEVCD_UNSUPPORTED_BIT_DEPTH;

    UEV_PARSE("log2_max_pic_order_cnt_lsb_minus4", value, ps_bitstrm);
    ps_sps->i1_log2_max_pic_order_cnt_lsb = value + 4;

    BITS_PARSE("sps_sub_layer_ordering_info_present_flag", value, ps_bitstrm, 1);
    ps_sps->i1_sps_sub_layer_ordering_info_present_flag = value;

    i = (ps_sps->i1_sps_sub_layer_ordering_info_present_flag ? 0 : (ps_sps->i1_sps_max_sub_layers - 1));
 for(; i < ps_sps->i1_sps_max_sub_layers; i++)
 {

         UEV_PARSE("max_dec_pic_buffering", value, ps_bitstrm);
         ps_sps->ai1_sps_max_dec_pic_buffering[i] = value + 1;

        if(ps_sps->ai1_sps_max_dec_pic_buffering[i] > MAX_DPB_SIZE)
        {
            return IHEVCD_INVALID_PARAMETER;
        }

         UEV_PARSE("num_reorder_pics", value, ps_bitstrm);
         ps_sps->ai1_sps_max_num_reorder_pics[i] = value;

        if(ps_sps->ai1_sps_max_num_reorder_pics[i] > ps_sps->ai1_sps_max_dec_pic_buffering[i])
        {
            return IHEVCD_INVALID_PARAMETER;
        }

         UEV_PARSE("max_latency_increase", value, ps_bitstrm);
         ps_sps->ai1_sps_max_latency_increase[i] = value;
     }
    UEV_PARSE("log2_min_coding_block_size_minus3", value, ps_bitstrm);
    ps_sps->i1_log2_min_coding_block_size = value + 3;

    UEV_PARSE("log2_diff_max_min_coding_block_size", value, ps_bitstrm);
    ps_sps->i1_log2_diff_max_min_coding_block_size = value;

    UEV_PARSE("log2_min_transform_block_size_minus2", value, ps_bitstrm);
    ps_sps->i1_log2_min_transform_block_size = value + 2;

    UEV_PARSE("log2_diff_max_min_transform_block_size", value, ps_bitstrm);
    ps_sps->i1_log2_diff_max_min_transform_block_size = value;

    ps_sps->i1_log2_max_transform_block_size = ps_sps->i1_log2_min_transform_block_size +
                    ps_sps->i1_log2_diff_max_min_transform_block_size;

    ps_sps->i1_log2_ctb_size = ps_sps->i1_log2_min_coding_block_size +
                    ps_sps->i1_log2_diff_max_min_coding_block_size;

 if((ps_sps->i1_log2_min_coding_block_size < 3) ||
 (ps_sps->i1_log2_min_transform_block_size < 2) ||
 (ps_sps->i1_log2_diff_max_min_transform_block_size < 0) ||
 (ps_sps->i1_log2_max_transform_block_size > ps_sps->i1_log2_ctb_size) ||
 (ps_sps->i1_log2_ctb_size < 4) ||
 (ps_sps->i1_log2_ctb_size > 6))
 {
 return IHEVCD_INVALID_PARAMETER;
 }

    ps_sps->i1_log2_min_pcm_coding_block_size = 0;
    ps_sps->i1_log2_diff_max_min_pcm_coding_block_size = 0;

    UEV_PARSE("max_transform_hierarchy_depth_inter", value, ps_bitstrm);
    ps_sps->i1_max_transform_hierarchy_depth_inter = value;

    UEV_PARSE("max_transform_hierarchy_depth_intra", value, ps_bitstrm);
    ps_sps->i1_max_transform_hierarchy_depth_intra = value;

 /* String has a d (enabled) in order to match with HM */
    BITS_PARSE("scaling_list_enabled_flag", value, ps_bitstrm, 1);
    ps_sps->i1_scaling_list_enable_flag = value;

 if(ps_sps->i1_scaling_list_enable_flag)
 {
        COPY_DEFAULT_SCALING_LIST(ps_sps->pi2_scaling_mat);
        BITS_PARSE("sps_scaling_list_data_present_flag", value, ps_bitstrm, 1);
        ps_sps->i1_sps_scaling_list_data_present_flag = value;

 if(ps_sps->i1_sps_scaling_list_data_present_flag)
            ihevcd_scaling_list_data(ps_codec, ps_sps->pi2_scaling_mat);
 }
 else
 {
        COPY_FLAT_SCALING_LIST(ps_sps->pi2_scaling_mat);
 }
 /* String is asymmetric_motion_partitions_enabled_flag instead of amp_enabled_flag in order to match with HM */
    BITS_PARSE("asymmetric_motion_partitions_enabled_flag", value, ps_bitstrm, 1);
    ps_sps->i1_amp_enabled_flag = value;

    BITS_PARSE("sample_adaptive_offset_enabled_flag", value, ps_bitstrm, 1);
    ps_sps->i1_sample_adaptive_offset_enabled_flag = value;

    BITS_PARSE("pcm_enabled_flag", value, ps_bitstrm, 1);
    ps_sps->i1_pcm_enabled_flag = value;

 if(ps_sps->i1_pcm_enabled_flag)
 {
        BITS_PARSE("pcm_sample_bit_depth_luma", value, ps_bitstrm, 4);
        ps_sps->i1_pcm_sample_bit_depth_luma = value + 1;

        BITS_PARSE("pcm_sample_bit_depth_chroma", value, ps_bitstrm, 4);
        ps_sps->i1_pcm_sample_bit_depth_chroma = value + 1;

        UEV_PARSE("log2_min_pcm_coding_block_size_minus3", value, ps_bitstrm);
        ps_sps->i1_log2_min_pcm_coding_block_size = value + 3;

        UEV_PARSE("log2_diff_max_min_pcm_coding_block_size", value, ps_bitstrm);
        ps_sps->i1_log2_diff_max_min_pcm_coding_block_size = value;
        BITS_PARSE("pcm_loop_filter_disable_flag", value, ps_bitstrm, 1);
        ps_sps->i1_pcm_loop_filter_disable_flag = value;

 }
    UEV_PARSE("num_short_term_ref_pic_sets", value, ps_bitstrm);
    ps_sps->i1_num_short_term_ref_pic_sets = value;

    ps_sps->i1_num_short_term_ref_pic_sets = CLIP3(ps_sps->i1_num_short_term_ref_pic_sets, 0, MAX_STREF_PICS_SPS);

 for(i = 0; i < ps_sps->i1_num_short_term_ref_pic_sets; i++)
        ihevcd_short_term_ref_pic_set(ps_bitstrm, &ps_sps->as_stref_picset[0], ps_sps->i1_num_short_term_ref_pic_sets, i, &ps_sps->as_stref_picset[i]);

    BITS_PARSE("long_term_ref_pics_present_flag", value, ps_bitstrm, 1);
    ps_sps->i1_long_term_ref_pics_present_flag = value;

 if(ps_sps->i1_long_term_ref_pics_present_flag)
 {
        UEV_PARSE("num_long_term_ref_pics_sps", value, ps_bitstrm);
        ps_sps->i1_num_long_term_ref_pics_sps = value;

 for(i = 0; i < ps_sps->i1_num_long_term_ref_pics_sps; i++)
 {
            BITS_PARSE("lt_ref_pic_poc_lsb_sps[ i ]", value, ps_bitstrm, ps_sps->i1_log2_max_pic_order_cnt_lsb);
            ps_sps->ai1_lt_ref_pic_poc_lsb_sps[i] = value;

            BITS_PARSE("used_by_curr_pic_lt_sps_flag[ i ]", value, ps_bitstrm, 1);
            ps_sps->ai1_used_by_curr_pic_lt_sps_flag[i] = value;
 }
 }

    BITS_PARSE("sps_temporal_mvp_enable_flag", value, ps_bitstrm, 1);
    ps_sps->i1_sps_temporal_mvp_enable_flag = value;

 /* Print matches HM 8-2 */
    BITS_PARSE("sps_strong_intra_smoothing_enable_flag", value, ps_bitstrm, 1);
    ps_sps->i1_strong_intra_smoothing_enable_flag = value;

    BITS_PARSE("vui_parameters_present_flag", value, ps_bitstrm, 1);
    ps_sps->i1_vui_parameters_present_flag = value;

 if(ps_sps->i1_vui_parameters_present_flag)
        ihevcd_parse_vui_parameters(ps_bitstrm,
 &ps_sps->s_vui_parameters,
                                    ps_sps->i1_sps_max_sub_layers - 1);

    BITS_PARSE("sps_extension_flag", value, ps_bitstrm, 1);

 {
        WORD32 numerator;
        WORD32 ceil_offset;

        ceil_offset = (1 << ps_sps->i1_log2_ctb_size) - 1;
        numerator = ps_sps->i2_pic_width_in_luma_samples;

        ps_sps->i2_pic_wd_in_ctb = ((numerator + ceil_offset) /
 (1 << ps_sps->i1_log2_ctb_size));

        numerator = ps_sps->i2_pic_height_in_luma_samples;
        ps_sps->i2_pic_ht_in_ctb = ((numerator + ceil_offset) /
 (1 << ps_sps->i1_log2_ctb_size));

        ps_sps->i4_pic_size_in_ctb = ps_sps->i2_pic_ht_in_ctb *
                        ps_sps->i2_pic_wd_in_ctb;

 if(0 == ps_codec->i4_sps_done)
            ps_codec->s_parse.i4_next_ctb_indx = ps_sps->i4_pic_size_in_ctb;

        numerator = ps_sps->i2_pic_width_in_luma_samples;
        ps_sps->i2_pic_wd_in_min_cb = numerator  /
 (1 << ps_sps->i1_log2_min_coding_block_size);

        numerator = ps_sps->i2_pic_height_in_luma_samples;
        ps_sps->i2_pic_ht_in_min_cb = numerator  /
 (1 << ps_sps->i1_log2_min_coding_block_size);
 }
 if((0 != ps_codec->i4_first_pic_done) &&
 ((ps_codec->i4_wd != ps_sps->i2_pic_width_in_luma_samples) ||
 (ps_codec->i4_ht != ps_sps->i2_pic_height_in_luma_samples)))
 {
        ps_codec->i4_reset_flag = 1;
        ps_codec->i4_error_code = IVD_RES_CHANGED;
 return (IHEVCD_ERROR_T)IHEVCD_FAIL;
 }

 /* Update display width and display height */
 {
        WORD32 disp_wd, disp_ht;
        WORD32 crop_unit_x, crop_unit_y;
        crop_unit_x = 1;
        crop_unit_y = 1;

 if(CHROMA_FMT_IDC_YUV420 == ps_sps->i1_chroma_format_idc)
 {
            crop_unit_x = 2;
            crop_unit_y = 2;
 }

        disp_wd = ps_sps->i2_pic_width_in_luma_samples;
        disp_wd -= ps_sps->i2_pic_crop_left_offset * crop_unit_x;
        disp_wd -= ps_sps->i2_pic_crop_right_offset * crop_unit_x;

        disp_ht = ps_sps->i2_pic_height_in_luma_samples;
        disp_ht -= ps_sps->i2_pic_crop_top_offset * crop_unit_y;
        disp_ht -= ps_sps->i2_pic_crop_bottom_offset * crop_unit_y;

 if((0 >= disp_wd) || (0 >= disp_ht))
 return IHEVCD_INVALID_PARAMETER;

        ps_codec->i4_disp_wd = disp_wd;
        ps_codec->i4_disp_ht = disp_ht;

        ps_codec->i4_wd = ps_sps->i2_pic_width_in_luma_samples;
        ps_codec->i4_ht = ps_sps->i2_pic_height_in_luma_samples;

 {
            WORD32 ref_strd;
            ref_strd = ALIGN32(ps_sps->i2_pic_width_in_luma_samples + PAD_WD);
 if(ps_codec->i4_strd < ref_strd)
 {
                ps_codec->i4_strd = ref_strd;
 }
 }

 if(0 == ps_codec->i4_share_disp_buf)
 {
 if(ps_codec->i4_disp_strd < ps_codec->i4_disp_wd)
 {
                ps_codec->i4_disp_strd = ps_codec->i4_disp_wd;
 }
 }
 else
 {
 if(ps_codec->i4_disp_strd < ps_codec->i4_strd)
 {
                ps_codec->i4_disp_strd = ps_codec->i4_strd;
 }
 }
 }

    ps_codec->i4_sps_done = 1;
 return ret;
}


int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
 void *pCmdData, uint32_t *replySize, void *pReplyData) {

 VisualizerContext * pContext = (VisualizerContext *)self;
 int retsize;

 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
 return -EINVAL;
 }

 switch (cmdCode) {
 case EFFECT_CMD_INIT:
 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
 return -EINVAL;
 }
 *(int *) pReplyData = Visualizer_init(pContext);
 break;
 case EFFECT_CMD_SET_CONFIG:
 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
 || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
 return -EINVAL;
 }
 *(int *) pReplyData = Visualizer_setConfig(pContext,
 (effect_config_t *) pCmdData);
 break;
 case EFFECT_CMD_GET_CONFIG:
 if (pReplyData == NULL || replySize == NULL ||
 *replySize != sizeof(effect_config_t)) {
 return -EINVAL;
 }
 Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
 break;
 case EFFECT_CMD_RESET:
 Visualizer_reset(pContext);
 break;
 case EFFECT_CMD_ENABLE:
 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
 return -EINVAL;
 }
 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
 return -ENOSYS;
 }
        pContext->mState = VISUALIZER_STATE_ACTIVE;
        ALOGV("EFFECT_CMD_ENABLE() OK");
 *(int *)pReplyData = 0;
 break;
 case EFFECT_CMD_DISABLE:
 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
 return -EINVAL;
 }
 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
 return -ENOSYS;
 }
        pContext->mState = VISUALIZER_STATE_INITIALIZED;
        ALOGV("EFFECT_CMD_DISABLE() OK");
 *(int *)pReplyData = 0;
 break;
 case EFFECT_CMD_GET_PARAM: {
 if (pCmdData == NULL ||
            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
            pReplyData == NULL || replySize == NULL ||
 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
 return -EINVAL;
 }
        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
 effect_param_t *p = (effect_param_t *)pReplyData;
        p->status = 0;
 *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
 if (p->psize != sizeof(uint32_t)) {
            p->status = -EINVAL;
 break;
 }
 switch (*(uint32_t *)p->data) {
 case VISUALIZER_PARAM_CAPTURE_SIZE:
            ALOGV("get mCaptureSize = %" PRIu32, pContext->mCaptureSize);
 *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
            p->vsize = sizeof(uint32_t);
 *replySize += sizeof(uint32_t);
 break;
 case VISUALIZER_PARAM_SCALING_MODE:
            ALOGV("get mScalingMode = %" PRIu32, pContext->mScalingMode);
 *((uint32_t *)p->data + 1) = pContext->mScalingMode;
            p->vsize = sizeof(uint32_t);
 *replySize += sizeof(uint32_t);
 break;
 case VISUALIZER_PARAM_MEASUREMENT_MODE:
            ALOGV("get mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
 *((uint32_t *)p->data + 1) = pContext->mMeasurementMode;
            p->vsize = sizeof(uint32_t);
 *replySize += sizeof(uint32_t);
 break;
 default:
            p->status = -EINVAL;
 }
 } break;
 case EFFECT_CMD_SET_PARAM: {
 if (pCmdData == NULL ||
            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
            pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
 return -EINVAL;
 }
 *(int32_t *)pReplyData = 0;
 effect_param_t *p = (effect_param_t *)pCmdData;
 if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
 *(int32_t *)pReplyData = -EINVAL;

             break;
         }
         switch (*(uint32_t *)p->data) {
        case VISUALIZER_PARAM_CAPTURE_SIZE:
            pContext->mCaptureSize = *((uint32_t *)p->data + 1);
            ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize);
            break;
         case VISUALIZER_PARAM_SCALING_MODE:
             pContext->mScalingMode = *((uint32_t *)p->data + 1);
             ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode);
             break;
        case VISUALIZER_PARAM_LATENCY:
            pContext->mLatency = *((uint32_t *)p->data + 1);
            ALOGV("set mLatency = %" PRIu32, pContext->mLatency);
            break;
         case VISUALIZER_PARAM_MEASUREMENT_MODE:
             pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
             ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
 break;
 default:
 *(int32_t *)pReplyData = -EINVAL;
 }
 } break;
 case EFFECT_CMD_SET_DEVICE:
 case EFFECT_CMD_SET_VOLUME:
 case EFFECT_CMD_SET_AUDIO_MODE:
 break;

 case VISUALIZER_CMD_CAPTURE: {
 uint32_t captureSize = pContext->mCaptureSize;
 if (pReplyData == NULL || replySize == NULL || *replySize != captureSize) {
            ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %" PRIu32 " captureSize %" PRIu32,
 *replySize, captureSize);
 return -EINVAL;
 }
 if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
 const uint32_t deltaMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);

 if ((pContext->mLastCaptureIdx == pContext->mCaptureIdx) &&
 (pContext->mBufferUpdateTime.tv_sec != 0) &&
 (deltaMs > MAX_STALL_TIME_MS)) {
                    ALOGV("capture going to idle");
                    pContext->mBufferUpdateTime.tv_sec = 0;
                    memset(pReplyData, 0x80, captureSize);
 } else {
 int32_t latencyMs = pContext->mLatency;
                latencyMs -= deltaMs;

                 if (latencyMs < 0) {
                     latencyMs = 0;
                 }
                const uint32_t deltaSmpl =
                    pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
                int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl;

                 if (capturePoint < 0) {
                     uint32_t size = -capturePoint;
                     if (size > captureSize) {
                        size = captureSize;
 }
                    memcpy(pReplyData,
                           pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
                           size);
                    pReplyData = (char *)pReplyData + size;
                    captureSize -= size;
                    capturePoint = 0;
 }
                memcpy(pReplyData,
                       pContext->mCaptureBuf + capturePoint,
                       captureSize);
 }

            pContext->mLastCaptureIdx = pContext->mCaptureIdx;
 } else {
            memset(pReplyData, 0x80, captureSize);
 }

 } break;

 case VISUALIZER_CMD_MEASURE: {
 if (pReplyData == NULL || replySize == NULL ||
 *replySize < (sizeof(int32_t) * MEASUREMENT_COUNT)) {
 if (replySize == NULL) {
                ALOGV("VISUALIZER_CMD_MEASURE() error replySize NULL");
 } else {
                ALOGV("VISUALIZER_CMD_MEASURE() error *replySize %" PRIu32
 " < (sizeof(int32_t) * MEASUREMENT_COUNT) %" PRIu32,
 *replySize,
 uint32_t(sizeof(int32_t)) * MEASUREMENT_COUNT);
 }
            android_errorWriteLog(0x534e4554, "30229821");
 return -EINVAL;
 }
 uint16_t peakU16 = 0;
 float sumRmsSquared = 0.0f;
 uint8_t nbValidMeasurements = 0;
 const int32_t delayMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);
 if (delayMs > DISCARD_MEASUREMENTS_TIME_MS) {
            ALOGV("Discarding measurements, last measurement is %" PRId32 "ms old", delayMs);
 for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) {
                pContext->mPastMeasurements[i].mIsValid = false;
                pContext->mPastMeasurements[i].mPeakU16 = 0;
                pContext->mPastMeasurements[i].mRmsSquared = 0;
 }
            pContext->mMeasurementBufferIdx = 0;
 } else {
 for (uint32_t i=0 ; i < pContext->mMeasurementWindowSizeInBuffers ; i++) {
 if (pContext->mPastMeasurements[i].mIsValid) {
 if (pContext->mPastMeasurements[i].mPeakU16 > peakU16) {
                        peakU16 = pContext->mPastMeasurements[i].mPeakU16;
 }
                    sumRmsSquared += pContext->mPastMeasurements[i].mRmsSquared;
                    nbValidMeasurements++;
 }
 }
 }
 float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements);
 int32_t* pIntReplyData = (int32_t*)pReplyData;
 if (rms < 0.000016f) {
            pIntReplyData[MEASUREMENT_IDX_RMS] = -9600; //-96dB
 } else {
            pIntReplyData[MEASUREMENT_IDX_RMS] = (int32_t) (2000 * log10(rms / 32767.0f));
 }
 if (peakU16 == 0) {
            pIntReplyData[MEASUREMENT_IDX_PEAK] = -9600; //-96dB
 } else {
            pIntReplyData[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peakU16 / 32767.0f));
 }
        ALOGV("VISUALIZER_CMD_MEASURE peak=%" PRIu16 " (%" PRId32 "mB), rms=%.1f (%" PRId32 "mB)",
                peakU16, pIntReplyData[MEASUREMENT_IDX_PEAK],
                rms, pIntReplyData[MEASUREMENT_IDX_RMS]);
 }
 break;

 default:
        ALOGW("Visualizer_command invalid command %" PRIu32, cmdCode);
 return -EINVAL;
 }

 return 0;
}

An information disclosure vulnerability in visualizer/EffectVisualizer.cpp in libeffects in Mediaserver could enable a local malicious application to access data outside of its permission levels. This issue is rated as Moderate because it could be used to access sensitive data without permission. Product: Android. Versions: 4.4.4, 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1. Android ID: A-31781965.


int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
 void *pCmdData, uint32_t *replySize, void *pReplyData) {

 VisualizerContext * pContext = (VisualizerContext *)self;
 int retsize;

 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
 return -EINVAL;
 }

 switch (cmdCode) {
 case EFFECT_CMD_INIT:
 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
 return -EINVAL;
 }
 *(int *) pReplyData = Visualizer_init(pContext);
 break;
 case EFFECT_CMD_SET_CONFIG:
 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
 || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
 return -EINVAL;
 }
 *(int *) pReplyData = Visualizer_setConfig(pContext,
 (effect_config_t *) pCmdData);
 break;
 case EFFECT_CMD_GET_CONFIG:
 if (pReplyData == NULL || replySize == NULL ||
 *replySize != sizeof(effect_config_t)) {
 return -EINVAL;
 }
 Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
 break;
 case EFFECT_CMD_RESET:
 Visualizer_reset(pContext);
 break;
 case EFFECT_CMD_ENABLE:
 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
 return -EINVAL;
 }
 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
 return -ENOSYS;
 }
        pContext->mState = VISUALIZER_STATE_ACTIVE;
        ALOGV("EFFECT_CMD_ENABLE() OK");
 *(int *)pReplyData = 0;
 break;
 case EFFECT_CMD_DISABLE:
 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
 return -EINVAL;
 }
 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
 return -ENOSYS;
 }
        pContext->mState = VISUALIZER_STATE_INITIALIZED;
        ALOGV("EFFECT_CMD_DISABLE() OK");
 *(int *)pReplyData = 0;
 break;
 case EFFECT_CMD_GET_PARAM: {
 if (pCmdData == NULL ||
            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
            pReplyData == NULL || replySize == NULL ||
 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
 return -EINVAL;
 }
        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
 effect_param_t *p = (effect_param_t *)pReplyData;
        p->status = 0;
 *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
 if (p->psize != sizeof(uint32_t)) {
            p->status = -EINVAL;
 break;
 }
 switch (*(uint32_t *)p->data) {
 case VISUALIZER_PARAM_CAPTURE_SIZE:
            ALOGV("get mCaptureSize = %" PRIu32, pContext->mCaptureSize);
 *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
            p->vsize = sizeof(uint32_t);
 *replySize += sizeof(uint32_t);
 break;
 case VISUALIZER_PARAM_SCALING_MODE:
            ALOGV("get mScalingMode = %" PRIu32, pContext->mScalingMode);
 *((uint32_t *)p->data + 1) = pContext->mScalingMode;
            p->vsize = sizeof(uint32_t);
 *replySize += sizeof(uint32_t);
 break;
 case VISUALIZER_PARAM_MEASUREMENT_MODE:
            ALOGV("get mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
 *((uint32_t *)p->data + 1) = pContext->mMeasurementMode;
            p->vsize = sizeof(uint32_t);
 *replySize += sizeof(uint32_t);
 break;
 default:
            p->status = -EINVAL;
 }
 } break;
 case EFFECT_CMD_SET_PARAM: {
 if (pCmdData == NULL ||
            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
            pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
 return -EINVAL;
 }
 *(int32_t *)pReplyData = 0;
 effect_param_t *p = (effect_param_t *)pCmdData;
 if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
 *(int32_t *)pReplyData = -EINVAL;

             break;
         }
         switch (*(uint32_t *)p->data) {
        case VISUALIZER_PARAM_CAPTURE_SIZE: {
            const uint32_t captureSize = *((uint32_t *)p->data + 1);
            if (captureSize > VISUALIZER_CAPTURE_SIZE_MAX) {
                android_errorWriteLog(0x534e4554, "31781965");
                *(int32_t *)pReplyData = -EINVAL;
                ALOGW("set mCaptureSize = %u > %u", captureSize, VISUALIZER_CAPTURE_SIZE_MAX);
            } else {
                pContext->mCaptureSize = captureSize;
                ALOGV("set mCaptureSize = %u", captureSize);
            }
            } break;
         case VISUALIZER_PARAM_SCALING_MODE:
             pContext->mScalingMode = *((uint32_t *)p->data + 1);
             ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode);
             break;
        case VISUALIZER_PARAM_LATENCY: {
            uint32_t latency = *((uint32_t *)p->data + 1);
            if (latency > MAX_LATENCY_MS) {
                latency = MAX_LATENCY_MS; // clamp latency b/31781965
            }
            pContext->mLatency = latency;
            ALOGV("set mLatency = %u", latency);
            } break;
         case VISUALIZER_PARAM_MEASUREMENT_MODE:
             pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
             ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
 break;
 default:
 *(int32_t *)pReplyData = -EINVAL;
 }
 } break;
 case EFFECT_CMD_SET_DEVICE:
 case EFFECT_CMD_SET_VOLUME:
 case EFFECT_CMD_SET_AUDIO_MODE:
 break;

 case VISUALIZER_CMD_CAPTURE: {
 uint32_t captureSize = pContext->mCaptureSize;
 if (pReplyData == NULL || replySize == NULL || *replySize != captureSize) {
            ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %" PRIu32 " captureSize %" PRIu32,
 *replySize, captureSize);
 return -EINVAL;
 }
 if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
 const uint32_t deltaMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);

 if ((pContext->mLastCaptureIdx == pContext->mCaptureIdx) &&
 (pContext->mBufferUpdateTime.tv_sec != 0) &&
 (deltaMs > MAX_STALL_TIME_MS)) {
                    ALOGV("capture going to idle");
                    pContext->mBufferUpdateTime.tv_sec = 0;
                    memset(pReplyData, 0x80, captureSize);
 } else {
 int32_t latencyMs = pContext->mLatency;
                latencyMs -= deltaMs;

                 if (latencyMs < 0) {
                     latencyMs = 0;
                 }
                uint32_t deltaSmpl = captureSize
                        + pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;

                // large sample rate, latency, or capture size, could cause overflow.
                // do not offset more than the size of buffer.
                if (deltaSmpl > CAPTURE_BUF_SIZE) {
                    android_errorWriteLog(0x534e4554, "31781965");
                    deltaSmpl = CAPTURE_BUF_SIZE;
                }

                int32_t capturePoint = pContext->mCaptureIdx - deltaSmpl;
                // a negative capturePoint means we wrap the buffer.
                 if (capturePoint < 0) {
                     uint32_t size = -capturePoint;
                     if (size > captureSize) {
                        size = captureSize;
 }
                    memcpy(pReplyData,
                           pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
                           size);
                    pReplyData = (char *)pReplyData + size;
                    captureSize -= size;
                    capturePoint = 0;
 }
                memcpy(pReplyData,
                       pContext->mCaptureBuf + capturePoint,
                       captureSize);
 }

            pContext->mLastCaptureIdx = pContext->mCaptureIdx;
 } else {
            memset(pReplyData, 0x80, captureSize);
 }

 } break;

 case VISUALIZER_CMD_MEASURE: {
 if (pReplyData == NULL || replySize == NULL ||
 *replySize < (sizeof(int32_t) * MEASUREMENT_COUNT)) {
 if (replySize == NULL) {
                ALOGV("VISUALIZER_CMD_MEASURE() error replySize NULL");
 } else {
                ALOGV("VISUALIZER_CMD_MEASURE() error *replySize %" PRIu32
 " < (sizeof(int32_t) * MEASUREMENT_COUNT) %" PRIu32,
 *replySize,
 uint32_t(sizeof(int32_t)) * MEASUREMENT_COUNT);
 }
            android_errorWriteLog(0x534e4554, "30229821");
 return -EINVAL;
 }
 uint16_t peakU16 = 0;
 float sumRmsSquared = 0.0f;
 uint8_t nbValidMeasurements = 0;
 const int32_t delayMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);
 if (delayMs > DISCARD_MEASUREMENTS_TIME_MS) {
            ALOGV("Discarding measurements, last measurement is %" PRId32 "ms old", delayMs);
 for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) {
                pContext->mPastMeasurements[i].mIsValid = false;
                pContext->mPastMeasurements[i].mPeakU16 = 0;
                pContext->mPastMeasurements[i].mRmsSquared = 0;
 }
            pContext->mMeasurementBufferIdx = 0;
 } else {
 for (uint32_t i=0 ; i < pContext->mMeasurementWindowSizeInBuffers ; i++) {
 if (pContext->mPastMeasurements[i].mIsValid) {
 if (pContext->mPastMeasurements[i].mPeakU16 > peakU16) {
                        peakU16 = pContext->mPastMeasurements[i].mPeakU16;
 }
                    sumRmsSquared += pContext->mPastMeasurements[i].mRmsSquared;
                    nbValidMeasurements++;
 }
 }
 }
 float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements);
 int32_t* pIntReplyData = (int32_t*)pReplyData;
 if (rms < 0.000016f) {
            pIntReplyData[MEASUREMENT_IDX_RMS] = -9600; //-96dB
 } else {
            pIntReplyData[MEASUREMENT_IDX_RMS] = (int32_t) (2000 * log10(rms / 32767.0f));
 }
 if (peakU16 == 0) {
            pIntReplyData[MEASUREMENT_IDX_PEAK] = -9600; //-96dB
 } else {
            pIntReplyData[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peakU16 / 32767.0f));
 }
        ALOGV("VISUALIZER_CMD_MEASURE peak=%" PRIu16 " (%" PRId32 "mB), rms=%.1f (%" PRId32 "mB)",
                peakU16, pIntReplyData[MEASUREMENT_IDX_PEAK],
                rms, pIntReplyData[MEASUREMENT_IDX_RMS]);
 }
 break;

 default:
        ALOGW("Visualizer_command invalid command %" PRIu32, cmdCode);
 return -EINVAL;
 }

 return 0;
}


void smp_process_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
 uint8_t* p = (uint8_t*)p_data;

   uint8_t reason = SMP_INVALID_PARAMETERS;

   SMP_TRACE_DEBUG("%s", __func__);
  p_cb->status = *(uint8_t*)p_data;

   if (smp_command_has_invalid_parameters(p_cb)) {
     smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
     return;
   }

   if (p != NULL) {
     STREAM_TO_UINT8(p_cb->peer_keypress_notification, p);
   } else {
    p_cb->peer_keypress_notification = BTM_SP_KEY_OUT_OF_RANGE;
 }
  p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT;
}

In smp_process_keypress_notification of smp_act.cc, there is a possible out of bounds read due to an incorrect bounds check. This could lead to remote information disclosure over Bluetooth with no additional execution privileges needed. User interaction is not needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android ID: A-111936834


void smp_process_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
 uint8_t* p = (uint8_t*)p_data;

   uint8_t reason = SMP_INVALID_PARAMETERS;

   SMP_TRACE_DEBUG("%s", __func__);

   if (smp_command_has_invalid_parameters(p_cb)) {
    if (p_cb->rcvd_cmd_len < 2) {  // 1 (opcode) + 1 (Notif Type) bytes
      android_errorWriteLog(0x534e4554, "111936834");
    }
     smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
     return;
   }

  p_cb->status = *(uint8_t*)p_data;

   if (p != NULL) {
     STREAM_TO_UINT8(p_cb->peer_keypress_notification, p);
   } else {
    p_cb->peer_keypress_notification = BTM_SP_KEY_OUT_OF_RANGE;
 }
  p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT;
}


tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE* p_rc_rsp,
                                 tBTA_AV_RC_MSG* p_msg, uint8_t* p_ctype) {
  tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT;
 uint8_t u8, pdu, *p;
 uint16_t u16;
  tAVRC_MSG_VENDOR* p_vendor = &p_msg->msg.vendor;

  pdu = *(p_vendor->p_vendor_data);
  p_rc_rsp->pdu = pdu;
 *p_ctype = AVRC_RSP_REJ;

 /* Check to ansure a  valid minimum meta data length */
 if ((AVRC_MIN_META_CMD_LEN + p_vendor->vendor_len) > AVRC_META_CMD_BUF_SIZE) {
 /* reject it */
    p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
    APPL_TRACE_ERROR("%s: Invalid meta-command length: %d", __func__,
                     p_vendor->vendor_len);
 return 0;
 }

 /* Metadata messages only use PANEL sub-unit type */
 if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL) {
    APPL_TRACE_DEBUG("%s: SUBUNIT must be PANEL", __func__);
 /* reject it */
    evt = 0;
    p_vendor->hdr.ctype = AVRC_RSP_NOT_IMPL;
    p_vendor->vendor_len = 0;
    p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
 } else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype)) {
    APPL_TRACE_DEBUG("%s: Invalid pdu/ctype: 0x%x, %d", __func__, pdu,
                     p_vendor->hdr.ctype);
 /* reject invalid message without reporting to app */
    evt = 0;
    p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
 } else {
 switch (pdu) {

       case AVRC_PDU_GET_CAPABILITIES:
         /* process GetCapabilities command without reporting the event to app */
         evt = 0;
         u8 = *(p_vendor->p_vendor_data + 4);
         p = p_vendor->p_vendor_data + 2;
         p_rc_rsp->get_caps.capability_id = u8;
         BE_STREAM_TO_UINT16(u16, p);
        if ((u16 != 1) || (p_vendor->vendor_len != 5)) {
           p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
         } else {
           p_rc_rsp->get_caps.status = AVRC_STS_NO_ERROR;
 if (u8 == AVRC_CAP_COMPANY_ID) {
 *p_ctype = AVRC_RSP_IMPL_STBL;
            p_rc_rsp->get_caps.count = p_bta_av_cfg->num_co_ids;
            memcpy(p_rc_rsp->get_caps.param.company_id,
                   p_bta_av_cfg->p_meta_co_ids,
 (p_bta_av_cfg->num_co_ids << 2));
 } else if (u8 == AVRC_CAP_EVENTS_SUPPORTED) {
 *p_ctype = AVRC_RSP_IMPL_STBL;
            p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
            memcpy(p_rc_rsp->get_caps.param.event_id,
                   p_bta_av_cfg->p_meta_evt_ids, p_bta_av_cfg->num_evt_ids);
 } else {
            APPL_TRACE_DEBUG("%s: Invalid capability ID: 0x%x", __func__, u8);
 /* reject - unknown capability ID */
            p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM;
 }
 }
 break;

 case AVRC_PDU_REGISTER_NOTIFICATION:
 /* make sure the event_id is implemented */
        p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id(p_vendor);
 if (p_rc_rsp->rsp.status != BTA_AV_STS_NO_RSP) evt = 0;
 break;
 }
 }

 return evt;
}

In bta_av_proc_meta_cmd of bta_av_act.cc, there is a possible out of bounds read due to an incorrect bounds check. This could lead to remote information disclosure over Bluetooth with no additional execution privileges needed. User interaction is not needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android-9.0 Android ID: A-111893951


tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE* p_rc_rsp,
                                 tBTA_AV_RC_MSG* p_msg, uint8_t* p_ctype) {
  tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT;
 uint8_t u8, pdu, *p;
 uint16_t u16;
  tAVRC_MSG_VENDOR* p_vendor = &p_msg->msg.vendor;

  pdu = *(p_vendor->p_vendor_data);
  p_rc_rsp->pdu = pdu;
 *p_ctype = AVRC_RSP_REJ;

 /* Check to ansure a  valid minimum meta data length */
 if ((AVRC_MIN_META_CMD_LEN + p_vendor->vendor_len) > AVRC_META_CMD_BUF_SIZE) {
 /* reject it */
    p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
    APPL_TRACE_ERROR("%s: Invalid meta-command length: %d", __func__,
                     p_vendor->vendor_len);
 return 0;
 }

 /* Metadata messages only use PANEL sub-unit type */
 if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL) {
    APPL_TRACE_DEBUG("%s: SUBUNIT must be PANEL", __func__);
 /* reject it */
    evt = 0;
    p_vendor->hdr.ctype = AVRC_RSP_NOT_IMPL;
    p_vendor->vendor_len = 0;
    p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
 } else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype)) {
    APPL_TRACE_DEBUG("%s: Invalid pdu/ctype: 0x%x, %d", __func__, pdu,
                     p_vendor->hdr.ctype);
 /* reject invalid message without reporting to app */
    evt = 0;
    p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
 } else {
 switch (pdu) {

       case AVRC_PDU_GET_CAPABILITIES:
         /* process GetCapabilities command without reporting the event to app */
         evt = 0;
        if (p_vendor->vendor_len != 5) {
          android_errorWriteLog(0x534e4554, "111893951");
          p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
          break;
        }
         u8 = *(p_vendor->p_vendor_data + 4);
         p = p_vendor->p_vendor_data + 2;
         p_rc_rsp->get_caps.capability_id = u8;
         BE_STREAM_TO_UINT16(u16, p);
        if (u16 != 1) {
           p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
         } else {
           p_rc_rsp->get_caps.status = AVRC_STS_NO_ERROR;
 if (u8 == AVRC_CAP_COMPANY_ID) {
 *p_ctype = AVRC_RSP_IMPL_STBL;
            p_rc_rsp->get_caps.count = p_bta_av_cfg->num_co_ids;
            memcpy(p_rc_rsp->get_caps.param.company_id,
                   p_bta_av_cfg->p_meta_co_ids,
 (p_bta_av_cfg->num_co_ids << 2));
 } else if (u8 == AVRC_CAP_EVENTS_SUPPORTED) {
 *p_ctype = AVRC_RSP_IMPL_STBL;
            p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
            memcpy(p_rc_rsp->get_caps.param.event_id,
                   p_bta_av_cfg->p_meta_evt_ids, p_bta_av_cfg->num_evt_ids);
 } else {
            APPL_TRACE_DEBUG("%s: Invalid capability ID: 0x%x", __func__, u8);
 /* reject - unknown capability ID */
            p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM;
 }
 }
 break;

 case AVRC_PDU_REGISTER_NOTIFICATION:
 /* make sure the event_id is implemented */
        p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id(p_vendor);
 if (p_rc_rsp->rsp.status != BTA_AV_STS_NO_RSP) evt = 0;
 break;
 }
 }

 return evt;
}


void mca_ccb_hdl_req(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
  BT_HDR* p_pkt = &p_data->hdr;
 uint8_t *p, *p_start;
  tMCA_DCB* p_dcb;
  tMCA_CTRL evt_data;
  tMCA_CCB_MSG* p_rx_msg = NULL;
 uint8_t reject_code = MCA_RSP_NO_RESOURCE;
 bool send_rsp = false;
 bool check_req = false;
 uint8_t reject_opcode;

  MCA_TRACE_DEBUG("mca_ccb_hdl_req status:%d", p_ccb->status);

   p_rx_msg = (tMCA_CCB_MSG*)p_pkt;
   p = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
   evt_data.hdr.op_code = *p++;
  BE_STREAM_TO_UINT16(evt_data.hdr.mdl_id, p);
   reject_opcode = evt_data.hdr.op_code + 1;

   MCA_TRACE_DEBUG("received mdl id: %d ", evt_data.hdr.mdl_id);
   if (p_ccb->status == MCA_CCB_STAT_PENDING) {
     MCA_TRACE_DEBUG("received req inpending state");
 /* allow abort in pending state */
 if ((p_ccb->status == MCA_CCB_STAT_PENDING) &&
 (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ)) {
      reject_code = MCA_RSP_SUCCESS;
      send_rsp = true;
 /* clear the pending status */
      p_ccb->status = MCA_CCB_STAT_NORM;
 if (p_ccb->p_tx_req &&
 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
        mca_dcb_dealloc(p_dcb, NULL);
        osi_free_and_reset((void**)&p_ccb->p_tx_req);
 }
 } else
      reject_code = MCA_RSP_BAD_OP;
 } else if (p_ccb->p_rx_msg) {
    MCA_TRACE_DEBUG("still handling prev req");
 /* still holding previous message, reject this new one ?? */

 } else if (p_ccb->p_tx_req) {
    MCA_TRACE_DEBUG("still waiting for a response ctrl_vpsm:0x%x",
                    p_ccb->ctrl_vpsm);
 /* sent a request; waiting for response */
 if (p_ccb->ctrl_vpsm == 0) {
      MCA_TRACE_DEBUG("local is ACP. accept the cmd from INT");
 /* local is acceptor, need to handle the request */
      check_req = true;
      reject_code = MCA_RSP_SUCCESS;
 /* drop the previous request */
 if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
        mca_dcb_dealloc(p_dcb, NULL);
 }
      osi_free_and_reset((void**)&p_ccb->p_tx_req);
      mca_stop_timer(p_ccb);
 } else {
 /*  local is initiator, ignore the req */
      osi_free(p_pkt);
 return;
 }
 } else if (p_pkt->layer_specific != MCA_RSP_SUCCESS) {
    reject_code = (uint8_t)p_pkt->layer_specific;
 if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
 (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
 (evt_data.hdr.op_code > MCA_LAST_SYNC_OP)) {
 /* invalid op code */
      reject_opcode = MCA_OP_ERROR_RSP;
      evt_data.hdr.mdl_id = 0;
 }
 } else {
    check_req = true;
    reject_code = MCA_RSP_SUCCESS;
 }

 if (check_req) {
 if (reject_code == MCA_RSP_SUCCESS) {
      reject_code = MCA_RSP_BAD_MDL;
 if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
 ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) &&
 (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ))) {
        reject_code = MCA_RSP_SUCCESS;
 /* mdl_id is valid according to the spec */
 switch (evt_data.hdr.op_code) {
 case MCA_OP_MDL_CREATE_REQ:
            evt_data.create_ind.dep_id = *p++;
            evt_data.create_ind.cfg = *p++;
            p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
 if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id)) {
              MCA_TRACE_ERROR("%s: Invalid local MDEP ID %d", __func__,
                              p_rx_msg->mdep_id);
              reject_code = MCA_RSP_BAD_MDEP;
 } else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) {
              MCA_TRACE_DEBUG("the mdl_id is currently used in the CL(create)");
              mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
 } else {
 /* check if this dep still have MDL available */
 if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0) {
                MCA_TRACE_ERROR("%s: MAX_MDL is used by MDEP %d", __func__,
                                evt_data.create_ind.dep_id);
                reject_code = MCA_RSP_MDEP_BUSY;
 }
 }
 break;

 case MCA_OP_MDL_RECONNECT_REQ:
 if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) {
              MCA_TRACE_ERROR("%s: MDL_ID %d busy, in CL(reconn)", __func__,
                              evt_data.hdr.mdl_id);
              reject_code = MCA_RSP_MDL_BUSY;
 }
 break;

 case MCA_OP_MDL_ABORT_REQ:
            reject_code = MCA_RSP_BAD_OP;
 break;

 case MCA_OP_MDL_DELETE_REQ:
 /* delete the associated mdl */
            mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
            send_rsp = true;
 break;
 }
 }
 }
 }

 if (((reject_code != MCA_RSP_SUCCESS) &&
 (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND)) ||
      send_rsp) {
    BT_HDR* p_buf = (BT_HDR*)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
    p_buf->offset = L2CAP_MIN_OFFSET;
    p = p_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
 *p++ = reject_opcode;
 *p++ = reject_code;
 bool valid_response = true;
 switch (reject_opcode) {
 case MCA_OP_ERROR_RSP:
 case MCA_OP_MDL_CREATE_RSP:
 case MCA_OP_MDL_RECONNECT_RSP:
 case MCA_OP_MDL_ABORT_RSP:
 case MCA_OP_MDL_DELETE_RSP:
        UINT16_TO_BE_STREAM(p, evt_data.hdr.mdl_id);
 break;
 case MCA_OP_SYNC_CAP_RSP:
        memset(p, 0, 7);
        p += 7;
 break;
 case MCA_OP_SYNC_SET_RSP:
        memset(p, 0, 14);
        p += 14;
 break;
 default:
        MCA_TRACE_ERROR("%s: reject_opcode 0x%02x not recognized", __func__,
                        reject_opcode);
        valid_response = false;
 break;
 }
 if (valid_response) {
      p_buf->len = p - p_start;
      MCA_TRACE_ERROR("%s: reject_opcode=0x%02x, reject_code=0x%02x, length=%d",
                      __func__, reject_opcode, reject_code, p_buf->len);
      L2CA_DataWrite(p_ccb->lcid, p_buf);
 } else {
      osi_free(p_buf);
 }
 }

 if (reject_code == MCA_RSP_SUCCESS) {
 /* use the received GKI buffer to store information to double check response
     * API */
    p_rx_msg->op_code = evt_data.hdr.op_code;
    p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
    p_ccb->p_rx_msg = p_rx_msg;
 if (send_rsp) {
      osi_free(p_pkt);
      p_ccb->p_rx_msg = NULL;
 }
    mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
 } else
    osi_free(p_pkt);
}

In mca_ccb_hdl_req of mca_cact.cc, there is a possible out of bounds read due to a missing bounds check. This could lead to remote information disclosure over Bluetooth with no additional execution privileges needed. User interaction is not needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android-9.0 Android ID: A-110791536


void mca_ccb_hdl_req(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
  BT_HDR* p_pkt = &p_data->hdr;
 uint8_t *p, *p_start;
  tMCA_DCB* p_dcb;
  tMCA_CTRL evt_data;
  tMCA_CCB_MSG* p_rx_msg = NULL;
 uint8_t reject_code = MCA_RSP_NO_RESOURCE;
 bool send_rsp = false;
 bool check_req = false;
 uint8_t reject_opcode;

  MCA_TRACE_DEBUG("mca_ccb_hdl_req status:%d", p_ccb->status);

   p_rx_msg = (tMCA_CCB_MSG*)p_pkt;
   p = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
   evt_data.hdr.op_code = *p++;
   reject_opcode = evt_data.hdr.op_code + 1;

  if (p_pkt->len >= 3) {
    BE_STREAM_TO_UINT16(evt_data.hdr.mdl_id, p);
  } else {
    android_errorWriteLog(0x534e4554, "110791536");
    evt_data.hdr.mdl_id = 0;
  }

   MCA_TRACE_DEBUG("received mdl id: %d ", evt_data.hdr.mdl_id);
   if (p_ccb->status == MCA_CCB_STAT_PENDING) {
     MCA_TRACE_DEBUG("received req inpending state");
 /* allow abort in pending state */
 if ((p_ccb->status == MCA_CCB_STAT_PENDING) &&
 (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ)) {
      reject_code = MCA_RSP_SUCCESS;
      send_rsp = true;
 /* clear the pending status */
      p_ccb->status = MCA_CCB_STAT_NORM;
 if (p_ccb->p_tx_req &&
 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
        mca_dcb_dealloc(p_dcb, NULL);
        osi_free_and_reset((void**)&p_ccb->p_tx_req);
 }
 } else
      reject_code = MCA_RSP_BAD_OP;
 } else if (p_ccb->p_rx_msg) {
    MCA_TRACE_DEBUG("still handling prev req");
 /* still holding previous message, reject this new one ?? */

 } else if (p_ccb->p_tx_req) {
    MCA_TRACE_DEBUG("still waiting for a response ctrl_vpsm:0x%x",
                    p_ccb->ctrl_vpsm);
 /* sent a request; waiting for response */
 if (p_ccb->ctrl_vpsm == 0) {
      MCA_TRACE_DEBUG("local is ACP. accept the cmd from INT");
 /* local is acceptor, need to handle the request */
      check_req = true;
      reject_code = MCA_RSP_SUCCESS;
 /* drop the previous request */
 if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
        mca_dcb_dealloc(p_dcb, NULL);
 }
      osi_free_and_reset((void**)&p_ccb->p_tx_req);
      mca_stop_timer(p_ccb);
 } else {
 /*  local is initiator, ignore the req */
      osi_free(p_pkt);
 return;
 }
 } else if (p_pkt->layer_specific != MCA_RSP_SUCCESS) {
    reject_code = (uint8_t)p_pkt->layer_specific;
 if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
 (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
 (evt_data.hdr.op_code > MCA_LAST_SYNC_OP)) {
 /* invalid op code */
      reject_opcode = MCA_OP_ERROR_RSP;
      evt_data.hdr.mdl_id = 0;
 }
 } else {
    check_req = true;
    reject_code = MCA_RSP_SUCCESS;
 }

 if (check_req) {
 if (reject_code == MCA_RSP_SUCCESS) {
      reject_code = MCA_RSP_BAD_MDL;
 if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
 ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) &&
 (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ))) {
        reject_code = MCA_RSP_SUCCESS;
 /* mdl_id is valid according to the spec */
 switch (evt_data.hdr.op_code) {
 case MCA_OP_MDL_CREATE_REQ:
            evt_data.create_ind.dep_id = *p++;
            evt_data.create_ind.cfg = *p++;
            p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
 if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id)) {
              MCA_TRACE_ERROR("%s: Invalid local MDEP ID %d", __func__,
                              p_rx_msg->mdep_id);
              reject_code = MCA_RSP_BAD_MDEP;
 } else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) {
              MCA_TRACE_DEBUG("the mdl_id is currently used in the CL(create)");
              mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
 } else {
 /* check if this dep still have MDL available */
 if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0) {
                MCA_TRACE_ERROR("%s: MAX_MDL is used by MDEP %d", __func__,
                                evt_data.create_ind.dep_id);
                reject_code = MCA_RSP_MDEP_BUSY;
 }
 }
 break;

 case MCA_OP_MDL_RECONNECT_REQ:
 if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) {
              MCA_TRACE_ERROR("%s: MDL_ID %d busy, in CL(reconn)", __func__,
                              evt_data.hdr.mdl_id);
              reject_code = MCA_RSP_MDL_BUSY;
 }
 break;

 case MCA_OP_MDL_ABORT_REQ:
            reject_code = MCA_RSP_BAD_OP;
 break;

 case MCA_OP_MDL_DELETE_REQ:
 /* delete the associated mdl */
            mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
            send_rsp = true;
 break;
 }
 }
 }
 }

 if (((reject_code != MCA_RSP_SUCCESS) &&
 (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND)) ||
      send_rsp) {
    BT_HDR* p_buf = (BT_HDR*)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
    p_buf->offset = L2CAP_MIN_OFFSET;
    p = p_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
 *p++ = reject_opcode;
 *p++ = reject_code;
 bool valid_response = true;
 switch (reject_opcode) {
 case MCA_OP_ERROR_RSP:
 case MCA_OP_MDL_CREATE_RSP:
 case MCA_OP_MDL_RECONNECT_RSP:
 case MCA_OP_MDL_ABORT_RSP:
 case MCA_OP_MDL_DELETE_RSP:
        UINT16_TO_BE_STREAM(p, evt_data.hdr.mdl_id);
 break;
 case MCA_OP_SYNC_CAP_RSP:
        memset(p, 0, 7);
        p += 7;
 break;
 case MCA_OP_SYNC_SET_RSP:
        memset(p, 0, 14);
        p += 14;
 break;
 default:
        MCA_TRACE_ERROR("%s: reject_opcode 0x%02x not recognized", __func__,
                        reject_opcode);
        valid_response = false;
 break;
 }
 if (valid_response) {
      p_buf->len = p - p_start;
      MCA_TRACE_ERROR("%s: reject_opcode=0x%02x, reject_code=0x%02x, length=%d",
                      __func__, reject_opcode, reject_code, p_buf->len);
      L2CA_DataWrite(p_ccb->lcid, p_buf);
 } else {
      osi_free(p_buf);
 }
 }

 if (reject_code == MCA_RSP_SUCCESS) {
 /* use the received GKI buffer to store information to double check response
     * API */
    p_rx_msg->op_code = evt_data.hdr.op_code;
    p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
    p_ccb->p_rx_msg = p_rx_msg;
 if (send_rsp) {
      osi_free(p_pkt);
      p_ccb->p_rx_msg = NULL;
 }
    mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
 } else
    osi_free(p_pkt);
}


static void sdp_copy_raw_data(tCONN_CB* p_ccb, bool offset) {
 unsigned int cpy_len, rem_len;
 uint32_t list_len;
 uint8_t* p;
 uint8_t type;

#if (SDP_DEBUG_RAW == TRUE)
 uint8_t num_array[SDP_MAX_LIST_BYTE_COUNT];
 uint32_t i;

 for (i = 0; i < p_ccb->list_len; i++) {
    snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X",
 (uint8_t)(p_ccb->rsp_list[i]));
 }
  SDP_TRACE_WARNING("result :%s", num_array);
#endif

 if (p_ccb->p_db->raw_data) {
    cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
    list_len = p_ccb->list_len;

     p = &p_ccb->rsp_list[0];

     if (offset) {
       type = *p++;
       p = sdpu_get_len_from_type(p, type, &list_len);
     }
     if (list_len < cpy_len) {
       cpy_len = list_len;
 }
    rem_len = SDP_MAX_LIST_BYTE_COUNT - (unsigned int)(p - &p_ccb->rsp_list[0]);
 if (cpy_len > rem_len) {
      SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len);
      cpy_len = rem_len;
 }
    SDP_TRACE_WARNING(
 "%s: list_len:%d cpy_len:%d p:%p p_ccb:%p p_db:%p raw_size:%d "
 "raw_used:%d raw_data:%p",
        __func__, list_len, cpy_len, p, p_ccb, p_ccb->p_db,
        p_ccb->p_db->raw_size, p_ccb->p_db->raw_used, p_ccb->p_db->raw_data);
    memcpy(&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
    p_ccb->p_db->raw_used += cpy_len;
 }
}

In sdp_copy_raw_data of sdp_discovery.cc, there is a possible out of bounds write due to an incorrect bounds check. This could lead to remote code execution over bluetooth with no additional execution privileges needed. User interaction is not needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android-9.0 Android ID: A-110216176


static void sdp_copy_raw_data(tCONN_CB* p_ccb, bool offset) {
 unsigned int cpy_len, rem_len;
 uint32_t list_len;
 uint8_t* p;
 uint8_t type;

#if (SDP_DEBUG_RAW == TRUE)
 uint8_t num_array[SDP_MAX_LIST_BYTE_COUNT];
 uint32_t i;

 for (i = 0; i < p_ccb->list_len; i++) {
    snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X",
 (uint8_t)(p_ccb->rsp_list[i]));
 }
  SDP_TRACE_WARNING("result :%s", num_array);
#endif

 if (p_ccb->p_db->raw_data) {
    cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
    list_len = p_ccb->list_len;

     p = &p_ccb->rsp_list[0];

     if (offset) {
      cpy_len -= 1;
       type = *p++;
      uint8_t* old_p = p;
       p = sdpu_get_len_from_type(p, type, &list_len);
      if ((int)cpy_len < (p - old_p)) {
        SDP_TRACE_WARNING("%s: no bytes left for data", __func__);
        return;
      }
      cpy_len -= (p - old_p);
     }
     if (list_len < cpy_len) {
       cpy_len = list_len;
 }
    rem_len = SDP_MAX_LIST_BYTE_COUNT - (unsigned int)(p - &p_ccb->rsp_list[0]);
 if (cpy_len > rem_len) {
      SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len);
      cpy_len = rem_len;
 }
    SDP_TRACE_WARNING(
 "%s: list_len:%d cpy_len:%d p:%p p_ccb:%p p_db:%p raw_size:%d "
 "raw_used:%d raw_data:%p",
        __func__, list_len, cpy_len, p, p_ccb, p_ccb->p_db,
        p_ccb->p_db->raw_size, p_ccb->p_db->raw_used, p_ccb->p_db->raw_data);
    memcpy(&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
    p_ccb->p_db->raw_used += cpy_len;
 }
}


 void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
     uint32_t size = data.readInt32();
    vector.insertAt((size_t)0, size);
    data.read(vector.editArray(), size);
 }

In readVector of iCrypto.cpp, there is a possible invalid read due to uninitialized data. This could lead to local information disclosure from the DRM server with no additional execution privileges needed. User interaction is not needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android-9.0 Android ID: A-79218474


 void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
     uint32_t size = data.readInt32();
    if (vector.insertAt((size_t)0, size) < 0) {
        vector.clear();
    }
    if (data.read(vector.editArray(), size) != NO_ERROR) {
        vector.clear();
        android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
    }
 }


SkCodec* SkIcoCodec::NewFromStream(SkStream* stream, Result* result) {
    std::unique_ptr<SkStream> inputStream(stream);

 static const uint32_t kIcoDirectoryBytes = 6;
 static const uint32_t kIcoDirEntryBytes = 16;

    std::unique_ptr<uint8_t[]> dirBuffer(new uint8_t[kIcoDirectoryBytes]);
 if (inputStream.get()->read(dirBuffer.get(), kIcoDirectoryBytes) !=
            kIcoDirectoryBytes) {
 SkCodecPrintf("Error: unable to read ico directory header.\n");
 *result = kIncompleteInput;
 return nullptr;
 }

 const uint16_t numImages = get_short(dirBuffer.get(), 4);
 if (0 == numImages) {
 SkCodecPrintf("Error: No images embedded in ico.\n");
 *result = kInvalidInput;
 return nullptr;
 }

 struct Entry {

         uint32_t offset;
         uint32_t size;
     };
    SkAutoFree dirEntryBuffer(sk_malloc_flags(sizeof(Entry) * numImages,
                                              SK_MALLOC_TEMP));
     if (!dirEntryBuffer) {
         SkCodecPrintf("Error: OOM allocating ICO directory for %i images.\n",
                       numImages);
 *result = kInternalError;
 return nullptr;
 }
 auto* directoryEntries = reinterpret_cast<Entry*>(dirEntryBuffer.get());

 for (uint32_t i = 0; i < numImages; i++) {
 uint8_t entryBuffer[kIcoDirEntryBytes];
 if (inputStream->read(entryBuffer, kIcoDirEntryBytes) !=
                kIcoDirEntryBytes) {
 SkCodecPrintf("Error: Dir entries truncated in ico.\n");
 *result = kIncompleteInput;
 return nullptr;
 }

 uint32_t size = get_int(entryBuffer, 8);

 uint32_t offset = get_int(entryBuffer, 12);

        directoryEntries[i].offset = offset;
        directoryEntries[i].size = size;
 }

 *result = kInvalidInput;

 struct EntryLessThan {
 bool operator() (Entry a, Entry b) const {
 return a.offset < b.offset;
 }
 };
 EntryLessThan lessThan;
 SkTQSort(directoryEntries, &directoryEntries[numImages - 1], lessThan);

 uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes;
    std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> codecs(
 new (SkTArray<std::unique_ptr<SkCodec>, true>)(numImages));
 for (uint32_t i = 0; i < numImages; i++) {
 uint32_t offset = directoryEntries[i].offset;
 uint32_t size = directoryEntries[i].size;

 if (offset < bytesRead) {
 SkCodecPrintf("Warning: invalid ico offset.\n");
 continue;
 }

 if (inputStream.get()->skip(offset - bytesRead) != offset - bytesRead) {
 SkCodecPrintf("Warning: could not skip to ico offset.\n");
 break;
 }

         bytesRead = offset;

        SkAutoFree buffer(sk_malloc_flags(size, 0));
         if (!buffer) {
             SkCodecPrintf("Warning: OOM trying to create embedded stream.\n");
             break;
 }

 if (inputStream->read(buffer.get(), size) != size) {
 SkCodecPrintf("Warning: could not create embedded stream.\n");
 *result = kIncompleteInput;
 break;
 }

        sk_sp<SkData> data(SkData::MakeFromMalloc(buffer.release(), size));
        std::unique_ptr<SkMemoryStream> embeddedStream(new SkMemoryStream(data));
        bytesRead += size;

 SkCodec* codec = nullptr;
 Result dummyResult;
 if (SkPngCodec::IsPng((const char*) data->bytes(), data->size())) {
            codec = SkPngCodec::NewFromStream(embeddedStream.release(), &dummyResult);
 } else {
            codec = SkBmpCodec::NewFromIco(embeddedStream.release(), &dummyResult);
 }

 if (nullptr != codec) {
            codecs->push_back().reset(codec);
 }
 }

 if (0 == codecs->count()) {
 SkCodecPrintf("Error: could not find any valid embedded ico codecs.\n");
 return nullptr;
 }

 size_t maxSize = 0;
 int maxIndex = 0;
 for (int i = 0; i < codecs->count(); i++) {
 SkImageInfo info = codecs->operator[](i)->getInfo();
 size_t size = info.getSafeSize(info.minRowBytes());

 if (size > maxSize) {
            maxSize = size;
            maxIndex = i;
 }
 }
 int width = codecs->operator[](maxIndex)->getInfo().width();
 int height = codecs->operator[](maxIndex)->getInfo().height();
 SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo();
 SkColorSpace* colorSpace = codecs->operator[](maxIndex)->getInfo().colorSpace();

 *result = kSuccess;
 return new SkIcoCodec(width, height, info, codecs.release(), sk_ref_sp(colorSpace));
}

In SkSampler::Fill of SkSampler.cpp, there is a possible out of bounds write due to an integer overflow. This could lead to remote code execution with no additional execution privileges needed. User interaction is needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android ID: A-78354855