728x90

어떤 칩셋은 정상동작하고 어떤 칩셋은 오동작이 발생한거 같다.

코드 사용 위치가 잘못되어 발생한 거 아닌가 싶다.


sendCommand() 는 Control transfer를 사용하여 Device로 Data를 보낸다.
UsbDeviceConnection.controlTransfer() 를 사용하여야 한다.

controlTransfer()의 proto type을 보면
public int controlTransfer (int requestType, int request, int value, int index, byte[] buffer, int length, int timeout)
requestType    request type for this transaction
request        request ID for this transaction
value        value field for this transaction
index        index field for this transaction
buffer        buffer for data portion of transaction, or null if no data needs to be sent or received
length        the length of the data to send or receive
timeout        in milliseconds


// for more info, search SET_LINE_CODING and SET_CONTROL_LINE_STATE in the document:
// "Universal Serial Bus Class Definitions for Communication Devices"

final int RQSID_SET_LINE_CODING = 0x20;
final int RQSID_SET_CONTROL_LINE_STATE = 0x22;

int usbResult;
usbResult = usbDeviceConnection.controlTransfer(0x21, // requestType
        RQSID_SET_CONTROL_LINE_STATE, // SET_CONTROL_LINE_STATE
        0, // value
        0, // index
        null, // buffer
        0, // length
        0); // timeout

// baud rate = 9600, 8 data bit, 1 stop bit
byte[] encodingSetting = new byte[] { (byte) 0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08 };
usbResult = usbDeviceConnection.controlTransfer(0x21, // requestType
        RQSID_SET_LINE_CODING, // SET_LINE_CODING
        0, // value
        0, // index
        encodingSetting, // buffer
        7, // length
        0); // timeout



블로그 이미지

Link2Me

,
728x90
USB Console 접속 코드를 구현해보는 중이다.

콘솔포트 - USB 케이블 - 스마트폰 연결을 하면 PC에 설치된 Android Studio 콘솔에서 Log 보는 것을 할 수가 없다.
에러가 발생하면 에러 메시지 분석이 쉽지 않다.

04-25 23:04:20.613: V/MainActivity(12928): VendorID : 1659 , ProductID : 8963
04-25 23:04:20.617: V/MainActivity(12928): controlTransfer(SET_CONTROL_LINE_STATE): 0
04-25 23:04:20.618: V/MainActivity(12928): controlTransfer(RQSID_SET_LINE_CODING): 7

04-25 23:20:54.285: V/MainActivity(18765): VendorID : 1027 , ProductID : 24577
04-25 23:20:54.289: V/MainActivity(18765): controlTransfer(SET_CONTROL_LINE_STATE): -1
04-25 23:20:54.291: V/MainActivity(18765): controlTransfer(RQSID_SET_LINE_CODING): -1


위와 같이 메시지가 스마트폰에 파일로 저장된다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Application이 원하는 장치에 대해서만 통보를 받을 수 있다. -->
    <!-- 0x0403 / 0x6001: FTDI FT232R UART -->
    <usb-device vendor-id="1027" product-id="24577" />
   
    <!-- 0x0403 / 0x6015: FTDI FT231X -->
    <usb-device vendor-id="1027" product-id="24597" />

    <!-- 0x2341 / Arduino -->
    <usb-device vendor-id="9025" />

    <!-- 0x16C0 / 0x0483: Teensyduino  -->
    <usb-device vendor-id="5824" product-id="1155" />

    <!-- 0x10C4 / 0xEA60: CP210x UART Bridge -->
    <usb-device vendor-id="4292" product-id="60000" />

    <!-- 0x1a86 / 0x7523: Qinheng CH340 -->
    <usb-device vendor-id="6790" product-id="29987" />

    <!-- 0x067B / 0x2303: Prolific PL2303 -->
    <usb-device vendor-id="1659" product-id="8963" />
    <usb-device vendor-id="1659" product-id="8964" />
    <usb-device vendor-id="1659" product-id="41216" />
    <!-- usb-device vendor-id="1659=0x067B" product-id="8963=0x2303" -->
    <!-- usb-device vendor-id="1659=0x067B" product-id="8964=0x2304" -->
    <!-- usb-device vendor-id="1659=0x067B" product-id="41216=0xA100" -->
</resources> 


칩셋이 FTDI 칩셋인 경우에 보여주는 메시지와 PL2303 칩셋일 때 보여주는 메시지가 다르다.
내가 테스트하는 코드가 PL2303은 정상적으로 잘 동작하는데 FTDI 칩셋은 오류를 뿌리고 바로 죽는다.

import android.os.Binder;
import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class LogWrapper {
    private static final String TAG = "LogWrapper";
    private static final int LOG_FILE_SIZE_LIMIT = 512 * 1024;
    private static final int LOG_FILE_MAX_COUNT = 2;
    private static final String LOG_FILE_NAME = "FileLog%g.txt";
    private static final SimpleDateFormat formatter =
            new SimpleDateFormat("MM-dd HH:mm:ss.SSS: ", Locale.getDefault());
    private static final Date date = new Date();
    private static Logger logger;
    private static FileHandler fileHandler;

    static {
        try {
            fileHandler = new FileHandler(Environment.getExternalStorageDirectory()
                    + File.separator +
                    LOG_FILE_NAME, LOG_FILE_SIZE_LIMIT, LOG_FILE_MAX_COUNT, true);
            fileHandler.setFormatter(new Formatter() {
                @Override
                public String format(LogRecord r) {
                    date.setTime(System.currentTimeMillis());

                    StringBuilder ret = new StringBuilder(80);
                    ret.append(formatter.format(date));
                    ret.append(r.getMessage());
                    return ret.toString();
                }
            });

            logger = Logger.getLogger(LogWrapper.class.getName());
            logger.addHandler(fileHandler);
            logger.setLevel(Level.ALL);
            logger.setUseParentHandlers(false);
            Log.d(TAG, "init success");
        } catch (IOException e) {
            Log.d(TAG, "init failure");
        }
    }

    public static void v(String tag, String msg) {
        if (logger != null) {
            logger.log(Level.INFO, String.format("V/%s(%d): %s\n",
                    tag, Binder.getCallingPid(), msg));
        }

        Log.v(tag, msg);
    }

}
 


위 코드의 출처는 https://abydos.tistory.com/23 이다.
테스트 결과 메시지가 출력되는 걸 확인할 수 있다.
Android Studio 에서 출력하는 완벽한 Log는 아니지만 에러가 발생하는 부분을 조금이라도 추적할 수는 있을 거 같다.
파일로 저장되므로 구글 드라이브에 공유로 폰에서 올리면 PC에서 EditPlus로 보기 편하게 볼 수 있더라.


아래 코드도 파일로 잘 저장된다.

    public static void writeLog(String str) {
        String str_Path_Full = Environment.getExternalStorageDirectory()
                .getAbsolutePath() + "/download/logdata.txt";
        File file = new File(str_Path_Full);
        if (file.exists() == false) {
            try {
                file.createNewFile();
            } catch (IOException e) {
            }
        } else {
            try {
                BufferedWriter bfw = new BufferedWriter(new FileWriter(str_Path_Full,true));
                bfw.write(str);
                bfw.write("\n");
                bfw.flush();
                bfw.close();
            } catch (FileNotFoundException e) {

            } catch (IOException e) {

            }
        }
    }


외부저장소에 저장하기 위해서는 위험권한을 설정해야만 저장되므로 관련 코드는 구현해야 한다.

TEDpermission 으로 권한 설정하면 쉽게 할 수 있다.

블로그 이미지

Link2Me

,
728x90

그림과 같이 에러 메시지가 나오는 경우가 생긴다.

Unable to resolve dependency




이 메시지가 나오는 원인은 27.+ 라고 되어 있기 때문이다.
+(동적버전번호)를 사용하면 예기치 않는 버전 업데이트를 초래하고 버전 차이점 문제 해결이 어려워질 수 있다.

27.1.1 로 수정하고 나서 에러 발생현상은 없어졌다.


블로그 이미지

Link2Me

,
728x90

컴파일을 시도했더니 이런 메시지가 나온다.

build\intermediates\instant_run_split_apk_resources\debug\instantRunSplitApkResourcesDebug\out\slice_2\resources_ap


해결방법


블로그 이미지

Link2Me

,
728x90

Handler는 잘 사용하지 않는데, Handler를 이용한 코딩이 필요하여 다시 Handler 개념 살펴보면서 적어둔다.


public class HandlerActivity extends AppCompatActivity {
    Handler mainThreadHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread);

        mainThreadHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if(msg.what == 1){
                }
            }
        };
    }
}

public class HandlerActivity extends AppCompatActivity {
    CHandler mainThreadHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread);

        mainThreadHandler = new Handler();
    }
    private class CHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what == 1){
                //handle message
            }
        }
    }
}


보통의 경우 위와 같이 Handler 클래스를 생성하는 방법으로 사용한다. 하지만 이런 방식의 경우 "The handler class should be static or leak might occur." 라는 메모리 누수 경고 문구가 발생할 수 있다.


Activity가 종료되더라도 Garbage collect 가 실행되지 않게 되고 결국 Message가 Message Queue에 상당 시간동안 남아있게 되어 Memory Leak 의 원인이 된다.


이를 해결할 방법은 static inner class 로 Handler를 정의해주고 WeakReference 를 이용하여 Activity 메소드를 호출하는 코드를 구현한다.


import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.lang.ref.WeakReference;

public class HandlerActivity extends AppCompatActivity {
    Button handlerStartButton;
    Button handlerStopButton;
    Handler mainThreadHandler;
    static TextView handlerExampleTextView;
    static int workValue = 0;
    boolean running = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);

        handlerStartButton = findViewById(R.id.btn_start);
        handlerStopButton = findViewById(R.id.btn_stop);
        handlerExampleTextView = findViewById(R.id.tv);

        mainThreadHandler = new MyHandler(this);

        handlerStartButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                running = true;
                startCount();
            }
        });
        handlerStopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                running = false;
                workValue = 0;
            }
        });
    }

    private void startCount(){
        // Start a child thread when button is clicked.
        WorkerThread thread = new WorkerThread();
        thread.start();
    }

    private static class MyHandler extends Handler{
        private final WeakReference<HandlerActivity> mActivity;

        private MyHandler(HandlerActivity activity) {
            mActivity = new WeakReference<HandlerActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            HandlerActivity activity = mActivity.get();
            if(activity != null){
                if(msg.what == 1){
                    handlerExampleTextView.setText("BackValue:" + workValue);
                }
            }
        }
    }

    private class WorkerThread extends Thread{
        @Override
        public void run() {
            super.run();
            while(running){
                workValue++;  // 작업스레드 값 증가
                try {
                    java.lang.Thread.sleep(1000); // 1000ms(1초)이므로 1초 단위로 실행
                    System.out.println(java.lang.Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // Create a message in child thread.
                Message childThreadMessage = new Message();
                childThreadMessage.what = 1;
                childThreadMessage.arg1 = workValue;
                // Put the message in main thread message queue.
                mainThreadHandler.sendMessage(childThreadMessage);
            }

        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_start"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:text="시작"/>
        <Button
            android:id="@+id/btn_stop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="중지"/>

    </LinearLayout>

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="결과"
        android:textSize="20dp"/>

</LinearLayout>


참조 : https://blog.naver.com/zoomen1004/220053616676


블로그 이미지

Link2Me

,
728x90

Materrial Design Bootstrap(MDB) 기반으로 코딩한 mobile Web에서 전화걸기 기능을 추가했다.

Android WebView 에서 모바일 Web을 Load하여 전화걸기 클릭을 하니까

err_unknown_url_scheme 에러 메시지를 뿌린다.


 public boolean shouldOverrideUrlLoading(WebView view, String url) {
    view.loadUrl(url);
    return true;
}

로 코드가 되어 있다.


전화걸기 tel:010-XXXX-YYYY 에 대한 예외처리 기능이 없어서 에러가 발생한 것이다.


아래와 같이 코드를 보완하고 나서 테스트하니 전화걸기가 잘 된다.

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith("tel:")) {
        Intent call_phone = new Intent(Intent.ACTION_CALL);
        call_phone.setData(Uri.parse(url));
        startActivity(call_phone); // 권한 설정은 Loing.java에서 처리했음
    } else if (url.startsWith("sms:")) {
        Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(url));
        startActivity(intent);
    } else if (url.startsWith("intent:")) {
        try {
            Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
            Intent existPackage = getPackageManager().getLaunchIntentForPackage(intent.getPackage());
            if (existPackage != null) {
                startActivity(intent);
            } else {
                Intent marketIntent = new Intent(Intent.ACTION_VIEW);
                marketIntent.setData(Uri.parse("market://details?id=" + intent.getPackage()));
                startActivity(marketIntent);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        view.loadUrl(url);
    }
    return true;
}





블로그 이미지

Link2Me

,
728x90

Web 사이트 개발을 하고 나서 취약점을 점검해볼 수 있는 TOOL 을 설치해봤다.

www.zaproxy.org/download/

에서 다운로드 한다.

 

 

지자체 사이트는 시험삼아 넣어봤더니 결과를 한참 늦게 피드백을 준다.

내 호스팅 사이트는 결과를 엄청 빠르게 보여준다.

보안 설정이 취약한 부분이 뭔지 결과를 경고 메시지로 보여준다.

 

Secure Coding 관련으로 공부를 좀 하고 경고 메시지가 없어지도록 해야겠다.

블로그 이미지

Link2Me

,