기존에 XDADevelopers 사이트에서 포팅해놓은 HTC WinMo 기기들의 한국 SMS 포팅 관련 문제가 있어서 이렇게 포스팅합니다.
실제로 저는 Xperia X1 (HTC Kovsky)를 가지고 있으며
xdandoid를 이용해 Froyo 버젼 제 스마트폰에 사용중입니다.
한국 SMS 문제를 정리하면 다음과 같습니다
- SMS 수신오류 - 잘못된 전화번호 / 메세지 없음
- SMS 발신오류 - 메세지 내용 깨짐 (인코딩 문제)
GSM SMS의 전송 규칙은 음... 네트워크의 DataGram같은 일종의 데이터 형식을 따르는데 이를 PDU라고 부릅니다.
PDU(Protocol Data Unit)는 SMS를 전송할 때 일종의 데이터 포맷인데 3GPP라는 기관에서 정한다고 합니다.
문자가 왔을 때 전송되는 SMS-DELIVERY PDU 문자열을 예로들면,
"0791280102198188440AA15117180890000401802291018263130A22080B811040309814F761623132B0A1B3AA"
이런식으로 PDU 문자열이 날아옵니다
이 PDU를 조각조각 분해하면 다음과 같은 결과가 나옵니다.
이전에 제가 안드로이드펍에서 SMS 분석 슬라이드를 본적이 있는데 링크를 까먹어서;
무책임하지만 그 슬라이드를 찾아서 확인해 보시면 매우 자세하게 SMS PDU구조가 나옵니다.
07 // SMSC octet size = 7
91 // type-of-address of the SMSC
280102198188 // service center +82102091888
44 // TP-UDHI(UserDataHeaderIndicator), TP-MMS(More messages to send)
0A // length of sender number
A1 // 1010 0001, national number/isdn/telephone numbering plan
5117180890 // 1571818009
00 // Protocol Identifier
84 // Data Coding Scheme 1000 0100
01802291018263 // 2010/08/22 19:10:28
13 // (User Data) length, 0x13 = 19
0A // (User Data) Header octet size = 10
22 // (User Data) type-of-address(toa)
08 // (User Data) type-of-protocol(TP)
0B // (User Data) length of local phone number, 0x0b = 11
81 // (User Data) 1000 0001, unknown/telephone numbering plan
101021436587 // (User Data), sender number 01012345678
61623132B0A1B3AA // (User Data) text message "ab12가나"
만일 이 SMS-DELIVERY PDU를 국내 SMS 처리가 안된 안드로이드 소스로 처리하게 되면
발신자: 1571818009
내용:(내용없음)
이런 식으로 SMS 가 도착합니다. 실제 발신자는 01012345678이고 내용은 "ab12가나"임에도 불구하고 말이죠;
이제 문제를 밝혀봅시다
1. 수신 문제의 첫번째 '메세지 없음'은 위에 빨간색으로 표시한 두부분에 의해서 발생합니다
첫째로 Data Coding Scheme에 0x80 비트는 미래를 위해 남겨놓은 그룹지정 비트입니다.
따라서 외국에서 개발된 소스에는 저 그룹지정 비트에 대한 어떠한 언급도 없죠. 그냥 Unknown Encoding Scheme입니다;
당연히 모르는 타입의 메세지를 더이상 처리안하고 넘어가는 경우가 많습니다. 따라서 메세지 수신시에 어떠한 내용도 표시되지 않죠;
=> RIL code에서 저 Data Coding Scheme을 처리해주던가
=> 또는 안드로이드 프레임워크내의 Telephony 소스에서 저 Data Coding Scheme에 대해서 처리할 수 있도록 변경해줘야합니다.
2. 이상한 번호로 문자가 오는 문제는 위에 파란색으로 표시한 부분에 의해 발생합니다.
위의 PDU 예에 따르면 보낸사람 번호는 "1571818009"이지 "01012345678"이 아닙니다;
당연히 문자를 보낸사람은 "1571818009"로 표시가 됩니다; 그리고 국내에서 사용한 전화번호는 밑에 User Data Header에 숨겨져 있네요;
=> Data Coding Scheme & 0x80 혹은 User DataHeaderNumberingPlan & 80 이라면 User Data Header에서 보낸사람 주소를 꺼내서 표시해줘야합니다. 이것도 역시 RIL SMS 코드내에서 수정을 하던가 혹은 안드로이드 Telephony 코드를 수정해야합니다
3. 보너스 문제로 한국어 인코딩 문제가 있습니다.
위 PDU 예에서 텍스트 메세지 "61623132B0A1B3AA" 가 "ab12가나"로 해석되어야합니다.
그런데 "61623132"는 쉽게 해석이 됩니다. 0x61 => 'a', 0x31 => '1' 이 부분은 ASCII 코드이면서 동시에 UTF-8 코드로 해석될 수 있죠.
문제는 "B0A1B3AA"가 왜 "가나"로 해석되냐 입니다. 실제로 GSM SMS 표준에 따르면 Data Coding Scheme으로 3가지가 가능합니다
- GSM7bit (Default 7bit 문자셋에 기반한 7bit 코딩입니다. 자세한건 패스;)
- 8bit (UTF-8)
- 16bit (UCS-2)
UTF-8 코딩에 따르면 "가나"같은 문자는 한 문자당 3byte로 변환이 됩니다;
위에 "B0A1B3AA"는 실제로 EUC-KR (KSC5601) 코딩을 사용하고 있습니다.
당연히 위에 GSM SMS의 Data Coding Scheme 표준에 따르지 않으므로 한글은 깨져서 해석이 됩니다;
이 문제를 해결하면 문자를 받았을 때 글자가 깨지는 문제가 없어지겠죠.
=> Data Coding Scheme & 0x80 이라면 메세지 내용을 EUC-KR => UTF-8 혹은 UCS-2 변환해야합니다
다행히도 C로 개발시에는 안드로이드 소스의 external/icu4c를 사용하시면 되고
Java에서는 스트링을 읽을때 String(text, "KSC5601") 하시면 될겁니다.
여기까지가 제가 문제를 확인하고 분석한 결과입니다.
마지막으로, 만일 SMS 소스 부분의 작업이 필요하시면 안드로이드 프레임워크내의 Telephony코드를 수정하라고 권해드리고 싶네요.
왜냐하면 어떤 스마트폰이냐에 상관없이 수정해야하는 SMS 코드이기 때문입니다.
음; 그러나 저는 불행히도 제가 빌드하지 않은 안드로이드 system.img를 사용하고 있기 때문에 RIL 코드를 수정해야 했습니다.
HTC ril 소스 부분은 정말 버그가 많네요; 제가 능력이 된다면 xdandroid 부분에 htc-ril 관련 소스 코드를 바로잡고 싶습니다.
기회가 될런지 모르겠네요.
틀린 부분이 있으면 지적해주시고
게시판을 잘못 찾아왔다면 역시 지적해주시고
뭔가 궁금한 부분이 있으시면 역시 질문해주시길 바랍니다.
그럼 저로인해 삽질이 조금이라도 줄어들기를 바라며 이만 줄입니다.
https://review.source.android.com/15305
이런 ChangeSet이 있습니다.
헌데 KT 단말에서는 수신에서 전혀 문제가 없고, SIM카드에서 메시지 꺼내 올때나 왕창 깨집니다. 요즘도 저런 현상이 일어나나요?
SKT 단말 등록해서 한번 봐야 하길 할텐데요;;;;
좋은 내용 감사드립니다.
저는 갤럭시S(M110S) 사용자인데요. 외국에서 SIM카드를 구입해서 사용하고 있습니다.
M110S에서 사용중인 문자메시지 프로그램이 삼성에서 제작한 것인데,
수신은 외국 통신망에서도 sms의 유니코드를 지원합니다.(sms 수신에는 전혀 문제가 없습니다.)
그런데 발신은 영어로만 가능한 상황입니다. 심지어 80byte 제한까지 걸려서요...(handcent를 사용하면 여전히 영어만 사용가능하지만 용량제한은 160byte로 늘어나긴 합니다.)
주말에 남는 시간을 이용해서 이 부분을 좀 고쳐보고 싶은데요.
멍게해삼 님께서 말씀해주신 것처럼 안드로이드 프레임워크내의 Telephony 코드를 수정해서 커널을 새로 얻으면 되려나요?
안드로이드 어플 개발에 경험이 없어 지식이 전무합니다. 제가 하고자 할 작업을 위해서 필요한 기초 강좌를 추천받을 수 있을까요?
잘 부탁드립니다^^;
AT&T향을 개발하며 국내에서 한글관련 수신에 문제가 있어 해당내용에 대해 조금 알고 있습니다.
일단 국내에서는 한글을 KSC5601로 전송하는 것 같습니다. (SKT 겔S는 안드로이드 Default Message App을 사용하지 않으므로..)
하지만 AT&T향을 하므로, 한글은 고려가 되지 않은 상태였고, 회사에서 국내에서 개발하는데 한글도 국내에서 개발폰 들고 일하는데 번거롭지 않다며 한글 수신이 안되는 문제를 해결하라고 하여 살펴보았습니다.
일단 떠도는 한글 Keyboard apk를 받아서 아래 Test Case를 수행햇습니다.
1. KT -> SKT (전송 문자는 abc test) 시 Encoding Type : ASCII 8bit, 화면 표시 안됨
2. SKT -> SKT (전송 문자는 abc test) 시 Encoding Type : GSM 7bit, 화면표시 됨
3. KT -> SKT (전송 문자는 한글 테스트) 시 Encoding Type : ASCII 8bit, 화면표시 안됨
4. SKT -> SKT (전송 문자는 한글 테스트) 시 Encoding Type : ASCII 8bit, 화면 표시 안됨
최초에(1990년대 최초 서비스시...) 한글처리를 유니코드가 아닌 KSC5601로 하였기 때문에....
전송시에 한글을 Unicode로 하여 보냈음에도, 8bit ASC로 수신되는건 아마도 국내의 SMSC에서,
유니코드로 온 한글을 강제로 KSC5601로 변환하는 것으로 판단됩니다. (그래야 기존의 피쳐폰들과 호환이 되니...)
국내 3G는 WCDMA(=GSM)이므로, 수신된 SMS의 문자열은 framework/base/telephony\java\com\android\internal\telephony\gsm\SmSmessage.java에 parseUserData()에서 처리됩니다.
그런데 상기에서 언급된 함수내에서 Encoding Type의 처리는 다음과 같습니다.
switch (encodingType)
{
case ENCODING_UNKNOWN:
case ENCODING_8BIT:
messageBody = null;
break;
case ENCODING_7BIT:
messageBody = p.getUserDataGSM7Bit(count);
break;
case ENCODING_16BIT:
messageBody = p.getUserDataUCS2(count);
break;
}
즉, endcoidng type이 8bit이면 message body(문자내용)이 null이 되어
실제 해당 문자 내용이 DB에 저장되지 않기 때문에 Message App에서 보이지 않습니다.
간단하게는 null부분을 messageBody = new String(tempUserData, "KSC5601");로 해주시면되고,
좀더 처리를 한다면 MCC(Mobile Country Code)와 MNC(Mobile Network Code)를 이용해 한국의 망을 잡고있으면 ksc5601로 변환한다던가 하는 추가를 하면 됩니다.
참고로 SKT-> AT&T Roaming폰으로 하면 AT&T폰에서는 Unicode로 정상적으로 수신하여 Message App에서 정상적으로 확인이 되며,
KT-> AT&T Romaing폰으로하면, AT&T폰에서 직접 문자를 확인하는 방시이아닌, Browser Link를 수신하고, 해당 Link를 선택하면,
JPG로 문자의 내용을 확인하도록 하게 되어있었습니다.
(KT쪽의 SMSC가 꼼수를....)
도움이 되기를...
Forrest
표준은 지켜주는 것이 좋은데... 그냥 써서 문제인듯하네요.