Log variables being sent to control socket in Android - android

This question was migrated from Android Enthusiasts Stack Exchange because it can be answered on Stack Overflow.
Migrated 22 days ago.
I'm having a hard time trying to get /system/bin/raccoon to log the variables being sent to it through the control socket. I can get it to log with any variables sent to the command line just fine but when I try to use an external app sending the variables to /dev/socket/raccoon I can't see them. What am I doing wrong? Below is the code. Thanks in advance
My logging code
FILE *filepntr = fopen("/sdcard/log.txt", "w");
fprintf(filepntr, "\nThis line was for shits and giggles");
fprintf(filepntr, "*argc: %d\n", *argc );
fprintf(filepntr, "*argv[0]: %s\n", *argv[0] );
if ( *argc == 1 ) {
fprintf(filepntr, "No arguments were passed.\n" );
} else {
fprintf(filepntr, "Arguments:\n" );
for ( i = 1; i < *argc; ++i ) {
fprintf(filepntr, " %d. %s\n", i, *argv[i] );
}
}
Below is the app code:
static int android_get_control_and_arguments(int *argc, char ***argv)
{
static char *args[32];
int control;
int i;
atexit(notify_death);
if ((i = android_get_control_socket("racoon")) == -1) {
return -1;
}
do_plog(LLV_DEBUG, "Waiting for control socket");
if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
do_plog(LLV_ERROR, "Cannot get control socket");
exit(1);
}
close(i);
fcntl(control, F_SETFD, FD_CLOEXEC);
args[0] = (*argv)[0];
for (i = 1; i < 32; ++i) {
unsigned char bytes[2];
if (recv(control, &bytes[0], 1, 0) != 1 ||
recv(control, &bytes[1], 1, 0) != 1) {
do_plog(LLV_ERROR, "Cannot get argument length");
exit(1);
} else {
int length = bytes[0] << 8 | bytes[1];
int offset = 0;
if (length == 0xFFFF) {
break;
}
args[i] = malloc(length + 1);
while (offset < length) {
int n = recv(control, &args[i][offset], length - offset, 0);
if (n > 0) {
offset += n;
} else {
do_plog(LLV_ERROR, "Cannot get argument value");
exit(1);
}
}
args[i][length] = 0;
}
}
do_plog(LLV_DEBUG, "\n*Received %s Arguments");
*argc = i;
*argv = args;
return control;
}

Related

android12 createSurface Unable to set size,android11 is ok

This code used to be android11,but android12 video Unable to set size.Always full screen.Whatever size is set. How should I use it normally. The problem was discovered while upgrading the Android version.Please help me!thanks.android Why change the usage of the underlying interface. Is there any good in it.
void createSubSurface(int winSize[]){
int z_order = INT_MAX - 10;
int x_pos=0,y_pos=0 ,pip_width=960,pip_height =540;
const int numFds = 0;
const int numInts = 3;
x_pos = winSize[0];
y_pos = winSize[1];
pip_width = winSize[2];
pip_height = winSize[3];
printf(" createSurface pip start\n");
m_composerClient_pip = SurfaceComposerClient::getDefault();
m_composerClient_pip->initCheck();
#if 0
const sp<IBinder> display2 = SurfaceComposerClient::getInternalDisplayToken();
DisplayInfo info2;
if(display2 != NULL){
SurfaceComposerClient::getDisplayInfo(display2, &info2);
}
#endif
//surface 2
m_surfaceControl_pip = m_composerClient_pip->createSurface(String8("V1"),pip_width, pip_height, PIXEL_FORMAT_RGB_888, 0);
printf(" createSurface2 m_surfaceControl_pip !=NULL ? %d\n",m_surfaceControl_pip!=NULL);
if(m_surfaceControl_pip !=NULL && m_surfaceControl_pip->isValid()){
printf(" createSurface2 isValid == true\n");
SurfaceComposerClient::Transaction{}
.setLayer(m_surfaceControl_pip, z_order)
.setAlpha(m_surfaceControl_pip, 1.0f)
.setPosition(m_surfaceControl_pip,x_pos,y_pos)
.setSize(m_surfaceControl_pip, pip_width,pip_height)
.show(m_surfaceControl_pip)
.apply();
m_surface_pip = m_surfaceControl_pip->getSurface();
}
if(m_surface_pip !=NULL){
for (int k = 0; k < 10; k++)
{
int status =native_window_api_connect(m_surface_pip.get(),NATIVE_WINDOW_API_MEDIA);
printf(" createSurface2 status = %d\n",status );
handle2= native_handle_create(numFds, numInts);
handle2->data[numFds] = 1;
handle2->data[numFds + 1] = 1;
handle2->data[numFds + 2] = SidebandClient::DVDPLAYER_V2;
native_window_set_sideband_stream(m_surface_pip.get(), handle2);
if(status == 0){
break;
}else{
printf(" createSurface2 native_window_api_connect != OK\n");
}
usleep(200000);
}
}
printf("\n createSurface2 OK \n");
}

I made Ping Program using C++, icmp. But it doesnt work on android

This is ping code. After select function, retval is just 0. I checked this is working good on mac os. and I checked a lot of ip. but it doesn't work only android device. I don't know what is problem. i made socket using SOCK_RAW at first time, but it works properly for superuser only. so i changed it SOCK_DGRAM. and it worked on mac os for normal user. Is it related to it?
int ping(string target)
{
int s, i, cc, packlen, datalen = DEFDATALEN;
struct hostent *hp;
struct sockaddr_in to, from;
struct ip *ip;
u_char *packet, outpack[MAXPACKET];
char hnamebuf[MAXHOSTNAMELEN];
string hostname;
struct icmp *icp;
int ret, fromlen, hlen;
fd_set rfds;
struct timeval tv;
int retval;
struct timeval start, end;
int end_t;
bool cont = true;
to.sin_family = AF_INET;
to.sin_addr.s_addr = htonl(inet_addr(target.c_str()));
//to.sin_port = 0;
if (to.sin_addr.s_addr != (u_int)-1)
{
hostname = target;
pErrorLabel->setString(hostname);
}
else
{
hp = gethostbyname(target.c_str());
if (!hp)
{
pErrorLabel->setString("Unknown host");
cerr << "unknown host " << target << endl;
return -1;
}
to.sin_family = hp->h_addrtype;
bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length);
strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
hostname = hnamebuf;
}
packlen = datalen + MAXIPLEN + MAXICMPLEN;
if ((packet = (u_char *)malloc((u_int)packlen)) == NULL)
{
pErrorLabel->setString("malloc error");
cerr << "malloc error\n";
return -1;
}
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)) < 0)
{
pErrorLabel->setString("administrator");
return -1; /* Needs to run as superuser!! */
}
icp = (struct icmp *)outpack;
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = 12345;
icp->icmp_id = getpid();
cc = datalen + ICMP_MINLEN;
icp->icmp_cksum = in_cksum((unsigned short *)icp, cc);
gettimeofday(&start, NULL);
i = sendto(s, (char *)outpack, cc, 0, (struct sockaddr*)&to, (socklen_t)sizeof(struct sockaddr_in));
if (i < 0 || i != cc)
{
if (i < 0)
perror("sendto error");
cout << "wrote " << hostname << " " << cc << " chars, ret= " << i << endl;
}
FD_ZERO(&rfds);
FD_SET(s, &rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
std::stringstream ss;
ss << "socket=" << (int)s;
pErrorLabel->setString(ss.str().c_str());
while (cont)
{
retval = select(s + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
{
perror("select()");
pErrorLabel->setString("select()");
return -1;
}
else if (retval)
{
fromlen = sizeof(sockaddr_in);
if ((ret = recvfrom(s, (char *)packet, packlen, 0, (struct sockaddr *)&from, (socklen_t*)&fromlen)) < 0)
{
perror("recvfrom error");
pErrorLabel->setString("recvfrom error");
return -1;
}
// Check the IP header
ip = (struct ip *)((char*)packet);
hlen = sizeof(struct ip);
if (ret < (hlen + ICMP_MINLEN))
{
cerr << "packet too short (" << ret << " bytes) from " << hostname << endl;;
return -1;
}
// Now the ICMP part
icp = (struct icmp *)(packet + hlen);
if (icp->icmp_type == ICMP_ECHOREPLY)
{
if (icp->icmp_seq != 12345)
{
cout << "received sequence # " << icp->icmp_seq << endl;
continue;
}
if (icp->icmp_id != getpid())
{
cout << "received id " << icp->icmp_id << endl;
continue;
}
cont = false;
}
else
{
continue;
}
gettimeofday(&end, NULL);
end_t = 1000000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);
if (end_t < 1)
end_t = 1;
cout << "Elapsed time = " << end_t << " usec" << endl;
return end_t;
}
else
{
cout << "No data within one seconds.\n";
return 0;
}
}
return 0;
}

How to solve Out of memory on a 19660816-byte allocation error in android?

I am converting a bitmap to base64 and getting Out of memory on a 19660816-byte allocation problem. Below is my code to endoce bitmap to base64,
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
String encoded = Base64Class.encode(b);
and my Base64Class code below:
public class Base64Class{
private Base64Class()
{
super();
}
/**
* Encode some data and return a String.
*/
public final static String encode(byte[] d)
{
if (d == null) return null;
byte data[] = new byte[d.length+2];
System.arraycopy(d, 0, data, 0, d.length);
byte dest[] = new byte[(data.length/3)*4];
// 3-byte to 4-byte conversion
for (int sidx = 0, didx=0; sidx < d.length; sidx += 3, didx += 4)
{
dest[didx] = (byte) ((data[sidx] >>> 2) & 077);
dest[didx+1] = (byte) ((data[sidx+1] >>> 4) & 017 |
(data[sidx] << 4) & 077);
dest[didx+2] = (byte) ((data[sidx+2] >>> 6) & 003 |
(data[sidx+1] << 2) & 077);
dest[didx+3] = (byte) (data[sidx+2] & 077);
}
// 0-63 to ascii printable conversion
for (int idx = 0; idx <dest.length; idx++)
{
if (dest[idx] < 26) dest[idx] = (byte)(dest[idx] + 'A');
else if (dest[idx] < 52) dest[idx] = (byte)(dest[idx] + 'a' - 26);
else if (dest[idx] < 62) dest[idx] = (byte)(dest[idx] + '0' - 52);
else if (dest[idx] < 63) dest[idx] = (byte)'+';
else dest[idx] = (byte)'/';
}
// add padding
for (int idx = dest.length-1; idx > (d.length*4)/3; idx--)
{
dest[idx] = (byte)'=';
}
return new String(dest);
}
/**
* Encode a String using Base64 using the default platform encoding
**/
public final static String encode(String s) {
return encode(s.getBytes());
}
/**
* Decode data and return bytes.
*/
public final static byte[] decode(String str)
{
if (str == null) return null;
byte data[] = str.getBytes();
return decode(data);
}
/**
* Decode data and return bytes. Assumes that the data passed
* in is ASCII text.
*/
public final static byte[] decode(byte[] data)
{
int tail = data.length;
while (data[tail-1] == '=') tail--;
byte dest[] = new byte[tail - data.length/4];
// ascii printable to 0-63 conversion
for (int idx = 0; idx <data.length; idx++)
{
if (data[idx] == '=') data[idx] = 0;
else if (data[idx] == '/') data[idx] = 63;
else if (data[idx] == '+') data[idx] = 62;
else if (data[idx] >= '0' && data[idx] <= '9')
data[idx] = (byte)(data[idx] - ('0' - 52));
else if (data[idx] >= 'a' && data[idx] <= 'z')
data[idx] = (byte)(data[idx] - ('a' - 26));
else if (data[idx] >= 'A' && data[idx] <= 'Z')
data[idx] = (byte)(data[idx] - 'A');
}
// 4-byte to 3-byte conversion
int sidx, didx;
for (sidx = 0, didx=0; didx < dest.length-2; sidx += 4, didx += 3)
{
dest[didx] = (byte) ( ((data[sidx] << 2) & 255) |
((data[sidx+1] >>> 4) & 3) );
dest[didx+1] = (byte) ( ((data[sidx+1] << 4) & 255) |
((data[sidx+2] >>> 2) & 017) );
dest[didx+2] = (byte) ( ((data[sidx+2] << 6) & 255) |
(data[sidx+3] & 077) );
}
if (didx < dest.length)
{
dest[didx] = (byte) ( ((data[sidx] << 2) & 255) |
((data[sidx+1] >>> 4) & 3) );
}
if (++didx < dest.length)
{
dest[didx] = (byte) ( ((data[sidx+1] << 4) & 255) |
((data[sidx+2] >>> 2) & 017) );
}
return dest;
}
/**
* A simple test that encodes and decodes the first commandline argument.
*/
public static final void main(String[] args)
{
if (args.length != 1)
{
System.out.println("Usage: Base64 string");
System.exit(0);
}
try
{
String e = Base64Class.encode(args[0].getBytes());
String d = new String(Base64Class.decode(e));
System.out.println("Input = '" + args[0] + "'");
System.out.println("Encoded = '" + e + "'");
System.out.println("Decoded = '" + d + "'");
}
catch (Exception x)
{
x.printStackTrace();
}
}
}

Parse CalendarContract.Events.DURATION values

I'm querying my calendar and showing all events result.
When i'm trying to parse the value CalendarContract.Events.DURATION i'm getting a RFC2445 string format.
For example i'm getting "P15M" which I know it's 15 minutes meeting.
After digging on the internet on how to parse RFC2445 I've found some google jar here
But is there any static class to parse those format?
Compiling a jar and using it only for 1 function it's not that nice...
Thanks for the help
I have had the same problem as you, dug around and found the following useful snippet somewhere. I refactored it a bit, so it will be more readable. hope it helps!
public static long RFC2445ToMilliseconds(String str)
{
if(str == null || str.isEmpty())
throw new IllegalArgumentException("Null or empty RFC string");
int sign = 1;
int weeks = 0;
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
int len = str.length();
int index = 0;
char c;
c = str.charAt(0);
if (c == '-')
{
sign = -1;
index++;
}
else if (c == '+')
index++;
if (len < index)
return 0;
c = str.charAt(index);
if (c != 'P')
throw new IllegalArgumentException("Duration.parse(str='" + str + "') expected 'P' at index="+ index);
index++;
c = str.charAt(index);
if (c == 'T')
index++;
int n = 0;
for (; index < len; index++)
{
c = str.charAt(index);
if (c >= '0' && c <= '9')
{
n *= 10;
n += ((int)(c-'0'));
}
else if (c == 'W')
{
weeks = n;
n = 0;
}
else if (c == 'H')
{
hours = n;
n = 0;
}
else if (c == 'M')
{
minutes = n;
n = 0;
}
else if (c == 'S')
{
seconds = n;
n = 0;
}
else if (c == 'D')
{
days = n;
n = 0;
}
else if (c == 'T')
{
}
else
throw new IllegalArgumentException ("Duration.parse(str='" + str + "') unexpected char '" + c + "' at index=" + index);
}
long factor = 1000 * sign;
long result = factor * ((7*24*60*60*weeks)
+ (24*60*60*days)
+ (60*60*hours)
+ (60*minutes)
+ seconds);
return result;
}
In while loop of cursor
String duration = "your duration";
try {
Duration d = new Duration();
d.parse(duration);
endMillis = startMillis + d.getMillis();
if (debug)
Log.d(TAG, "startMillis! " + startMillis);
if (debug)
Log.d(TAG, "endMillis! " + endMillis);
if (endMillis < startMillis) {
continue;
}
} catch (DateException e) {
if (debug)
Log.d(TAG, "duration:" + e.toString());
continue;
}
The class Duration is and also refer line number 1487. there is parsing logic , you just need to include duration class in your source code and parse as in try block.
I hope it helps

Android ADK with PC as USB Host with libusb, bulk transfer error

I'm trying to make my PC the USB Host for Android 2.3.4 devices in order to be able to develop APIs without needing actual "accessories". To do this, I need to establish the PC as the USB Host and the "device" (in my case a Nexus One running 2.3.4).
I started with libusb code from http://android.serverbox.ch/ as a base for the PC side and the DemoKit code and Android documentation on the Android side.
The two seems to negotiate the connection fine, and the interface gets "claimed" but dies on the actual attempt at bulk transfer. On OSX, the error is -5 (LIBUSB_ERROR_NOT_FOUND) and on Ubuntu Linux (as root) the error is -1 (LIBUSB_ERROR_IO). (Most recent releases of each with most recent libusb 1.0.8).
Here's the code. Other comments on problems welcome, though this is mostly a proof-of-concept, so I'm really just looking for the reason the bulk transfer isn't working:
#include <stdio.h>
#include <libusb.h>
#include <string.h>
#define ENDPOINT_BULK_IN 0x83
#define ENDPOINT_BULK_OUT 0x03 // Have tried 0x00, 0x01 and 0x02
#define VID 0x18D1
#define PID 0x4E11
#define ACCESSORY_PID 0x2D00
#define ACCESSORY_ADB_PID 0x2D01 // Can't get this to work, if ADB is active, can't get handle on device
/*
ON OSX
gcc adktest.c -I/usr/local/include -o adktest -lusb-1.0.0 -I/usr/local/include -I/usr/local/include/libusb-1.0
ON UBUNTU
gcc adktest.c -I/usr/include -o adktest -lusb-1.0 -I/usr/include -I/usr/include/libusb-1.0
Testing on Nexus One with Gingerbread 2.3.4
*/
static int transferTest();
static int init(void);
static int shutdown(void);
static void error(int code);
static void status(int code);
static int setupAccessory(
const char* manufacturer,
const char* modelName,
const char* description,
const char* version,
const char* uri,
const char* serialNumber);
//static
static struct libusb_device_handle* handle;
int main (int argc, char *argv[]){
if(init() < 0)
return;
if(setupAccessory(
"PCHost",
"PCHost1",
"Description",
"1.0",
"http://www.mycompany.com",
"SerialNumber") < 0){
fprintf(stdout, "Error setting up accessory\n");
shutdown();
return -1;
};
if(transferTest() < 0){
fprintf(stdout, "Error in transferTest\n");
shutdown();
return -1;
}
shutdown();
fprintf(stdout, "Finished\n");
return 0;
}
static int transferTest(){
// TEST BULK IN/OUT
const static int PACKET_BULK_LEN=64;
const static int TIMEOUT=5000;
int r,i;
int transferred;
char answer[PACKET_BULK_LEN];
char question[PACKET_BULK_LEN];
for (i=0;i<PACKET_BULK_LEN; i++) question[i]=i;
// ***FAILS HERE***
r = libusb_bulk_transfer(handle, ENDPOINT_BULK_OUT, question, PACKET_BULK_LEN,
&transferred,TIMEOUT);
if (r < 0) {
fprintf(stderr, "Bulk write error %d\n", r);
error(r);
return r;
}
fprintf(stdout, "Wrote %d bytes", r);
r = libusb_bulk_transfer(handle, ENDPOINT_BULK_IN, answer,PACKET_BULK_LEN,
&transferred, TIMEOUT);
if (r < 0) {
fprintf(stderr, "Bulk read error %d\n", r);
error(r);
return r;
}
fprintf(stdout, "Read %d bytes", r);
if (transferred < PACKET_BULK_LEN) {
fprintf(stderr, "Bulk transfer short read (%d)\n", r);
error(r);
return -1;
}
printf("Bulk Transfer Loop Test Result:\n");
// for (i=0;i< PACKET_BULK_LEN;i++) printf("%i, %i,\n ",question[i],answer[i]);
for(i = 0;i < PACKET_BULK_LEN; i++) {
if(i%8 == 0)
printf("\n");
printf("%02x, %02x; ",question[i],answer[i]);
}
printf("\n\n");
return 0;
}
static int init(){
libusb_init(NULL);
if((handle = libusb_open_device_with_vid_pid(NULL, VID, PID)) == NULL){
fprintf(stdout, "Problem acquiring handle\n");
return -1;
}
libusb_claim_interface(handle, 0);
return 0;
}
static int shutdown(){
if(handle != NULL)
libusb_release_interface (handle, 0);
libusb_exit(NULL);
return 0;
}
static int setupAccessory(
const char* manufacturer,
const char* modelName,
const char* description,
const char* version,
const char* uri,
const char* serialNumber){
unsigned char ioBuffer[2];
int devVersion;
int response;
response = libusb_control_transfer(
handle, //handle
0xC0, //bmRequestType
51, //bRequest
0, //wValue
0, //wIndex
ioBuffer, //data
2, //wLength
0 //timeout
);
if(response < 0){error(response);return-1;}
devVersion = ioBuffer[1] << 8 | ioBuffer[0];
fprintf(stdout,"Version Code Device: %d\n", devVersion);
usleep(1000);//sometimes hangs on the next transfer :(
response = libusb_control_transfer(handle,0x40,52,0,0,(char*)manufacturer,strlen(manufacturer),0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,1,(char*)modelName,strlen(modelName)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,2,(char*)description,strlen(description)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,3,(char*)version,strlen(version)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,4,(char*)uri,strlen(uri)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,5,(char*)serialNumber,strlen(serialNumber)+1,0);
if(response < 0){error(response);return -1;}
fprintf(stdout,"Accessory Identification sent\n", devVersion);
response = libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0);
if(response < 0){error(response);return -1;}
fprintf(stdout,"Attempted to put device into accessory mode\n", devVersion);
if(handle != NULL)
libusb_release_interface (handle, 0);
int tries = 4;
for(;;){
tries--;
if((handle = libusb_open_device_with_vid_pid(NULL, VID, ACCESSORY_PID)) == NULL){
if(tries < 0){
return -1;
}
}else{
break;
}
sleep(1);
}
libusb_claim_interface(handle, 0);
fprintf(stdout, "Interface claimed, ready to transfer data\n");
return 0;
}
// error reporting function left out for brevity
And here's the Android app:
package com.cengen.android.pchost;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import com.android.future.usb.UsbAccessory;
import com.android.future.usb.UsbManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MainActivity extends Activity implements Runnable
{
private final Logger logger = LoggerFactory.getLogger("PCHost");
private UsbManager usbManager;
UsbAccessory accessory;
ParcelFileDescriptor accessoryFileDescriptor;
FileInputStream accessoryInput;
FileOutputStream accessoryOutput;
private final BroadcastReceiver usbBroadcastReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action))
{
synchronized (this)
{
accessory = UsbManager.getAccessory(intent);
}
}
else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action))
{
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (accessory != null)
{
// call your method that cleans up and closes communication with the accessory
}
}
}
};
Handler messageHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case 1:
logger.info("Got message type {}", msg.what);
// SendFileMessage m = (SendFileMessage) msg.obj;
// handleSendFile(m);
break;
case 2:
logger.info("Got message type {}", msg.what);
// SendFileMessage m = (SendFileMessage) msg.obj;
// handleSendFile(m);
break;
case 3:
logger.info("Got message type {}", msg.what);
// SendFileMessage m = (SendFileMessage) msg.obj;
// handleSendFile(m);
break;
}
}
};
/**
* Main USB reading loop, processing incoming data from accessory and parsing
* it into messages via the defined format.
*/
public void run()
{
int ret = 0;
byte[] buffer = new byte[16384];
int i;
while (ret >= 0)
{
try
{
ret = accessoryInput.read(buffer);
logger.debug("Read {} bytes.", ret);
}
catch (IOException e)
{
logger.debug("Exception in USB accessory input reading", e);
break;
}
i = 0;
while (i < ret)
{
int len = ret - i;
switch (buffer[i])
{
case 0x1:
if (len >= 3)
{
Message m = Message.obtain(messageHandler, 1);
// m.obj = new MessageTypeOne(buffer[i + 1], buffer[i + 2]);
messageHandler.sendMessage(m);
}
i += 3;
break;
case 0x4:
if (len >= 3)
{
Message m = Message.obtain(messageHandler, 1);
// m.obj = new MessageTypeTwo(buffer[i + 1], buffer[i + 2]);
messageHandler.sendMessage(m);
}
i += 3;
break;
default:
logger.debug("unknown msg: " + buffer[i]);
i = len;
break;
}
}
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
usbManager = UsbManager.getInstance(this);
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(usbBroadcastReceiver, filter);
if (getLastNonConfigurationInstance() != null)
{
accessory = (UsbAccessory) getLastNonConfigurationInstance();
openAccessory(accessory);
}
setContentView(R.layout.main);
}
#Override
public Object onRetainNonConfigurationInstance()
{
return accessory != null ? accessory : super.onRetainNonConfigurationInstance();
}
#Override
public void onResume()
{
super.onResume();
Intent intent = getIntent();
if (accessoryInput != null && accessoryOutput != null)
return;
// TODO: verify, docs don't do this simple thing, not sure why?
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (accessory != null)
openAccessory(accessory);
else
logger.error("Failed to resume accessory.");
}
#Override
public void onPause()
{
super.onPause();
closeAccessory();
}
#Override
public void onDestroy()
{
unregisterReceiver(usbBroadcastReceiver);
super.onDestroy();
}
private void openAccessory(UsbAccessory accessory)
{
accessoryFileDescriptor = usbManager.openAccessory(accessory);
if (accessoryFileDescriptor != null)
{
this.accessory = accessory;
FileDescriptor fd = accessoryFileDescriptor.getFileDescriptor();
accessoryInput = new FileInputStream(fd);
accessoryOutput = new FileOutputStream(fd);
Thread thread = new Thread(null, this, "AndroidPCHost");
thread.start();
logger.debug("accessory opened");
// TODO: enable USB operations in the app
}
else
{
logger.debug("accessory open fail");
}
}
private void closeAccessory()
{
// TODO: disable USB operations in the app
try
{
if (accessoryFileDescriptor != null)
accessoryFileDescriptor.close();
}
catch (IOException e)
{}
finally
{
accessoryFileDescriptor = null;
accessory = null;
}
}
}
And the manifest (including the intent-filtering so it auto-associates and auto-perms the device, according to the docs):
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.android.pchost"
android:versionCode="1"
android:versionName="1.0">
<uses-feature android:name="android.hardware.usb.accessory" />
<uses-sdk android:minSdkVersion="10" />
<application android:label="#string/app_name" android:icon="#drawable/icon">
<uses-library android:name="com.android.future.usb.accessory" />
<activity android:name="MainActivity"
android:label="#string/app_name"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="#xml/accessory_filter" />
</activity>
</application>
</manifest>
Initial problem is that the original connection to the device in order to tell it to go into accessory mode is never closed. The USB subsystem and/or libusb do not throw an error if you then reopen and claim an interface while the original device is still left open. You only get an IO or NOT FOUND error when you actually try to write to/from an endpoint.
By adding:
libusb_close(handle);
within the if statement where the initial interface is released from initial connection the libusb side of the issue is resolved.
The next issue that prevents data to pass in this particular combination of softwares, is that the Android side is waiting for a larger segment of bytes before it accepts the read which results in a timeout (haven't worked out due to which side yet) and so if you set the buffer to match the libusb side (64), you will get an initial set of bytes written from the PC to the Android device. The software will still break after that since the PC/libusb side then tries to read data but the Android side isn't writing any, but that is simply unfinished software and not within the scope of the question.
The code example is very helpful, it just needs some modifications to work on Windows using libusb and installing WinUSB drivers via Zadig.
#include <stdio.h>
#include <libusb.h>
#include <string.h>
#ifdef _WIN32
#include <Windows.h>
#define sleep Sleep
#else
#include <unistd.h>
#endif
#define ENDPOINT_BULK_IN 0x83
#define ENDPOINT_BULK_OUT 0x03 // Have tried 0x00, 0x01 and 0x02
#define VID 0x18D1
#define PID 0x4E11
#define ACCESSORY_PID 0x2D00
#define ACCESSORY_ADB_PID 0x2D01 // Can't get this to work, if ADB is active, can't get handle on device
#define PACKET_BULK_LEN 64
#define TIMEOUT 5000
static int transferTest(void);
static int setupAccessory(
const char* manufacturer,
const char* modelName,
const char* description,
const char* version,
const char* uri,
const char* serialNumber);
//static
static struct libusb_device_handle* handle;
int main (int argc, char *argv[])
{
int r, tries;
libusb_init(NULL);
if((handle = libusb_open_device_with_vid_pid(NULL, VID, PID)) != NULL)
{
libusb_claim_interface(handle, 0);
r = setupAccessory("PCHost",
"PCHost1",
"Description",
"1.0",
"http://www.mycompany.com",
"SerialNumber");
libusb_release_interface (handle, 0);
libusb_close(handle);
if (r < 0)
{
libusb_exit(NULL);
fprintf(stdout, "Error setting up accessory\n");
return -1;
}
}
tries = 4;
for(;;)
{
tries--;
if((handle = libusb_open_device_with_vid_pid(NULL, VID, ACCESSORY_PID)) == NULL)
{
if(tries < 0)
{
libusb_exit(NULL);
fprintf(stdout, "Problem acquiring handle\n");
return -1;
}
}
else
{
break;
}
sleep(1);
}
libusb_claim_interface(handle, 0);
fprintf(stdout, "Interface claimed, ready to transfer data\n");
r = transferTest();
libusb_release_interface (handle, 0);
libusb_close(handle);
libusb_exit(NULL);
if (r < 0)
{
fprintf(stdout, "Error in transferTest\n");
return -1;
}
fprintf(stdout, "Finished\n");
return 0;
}
static int transferTest(void)
{
// TEST BULK IN/OUT
int r,i;
int transferred;
unsigned char answer[PACKET_BULK_LEN];
unsigned char question[PACKET_BULK_LEN];
struct libusb_device* device;
struct libusb_config_descriptor* config;
struct libusb_interface_descriptor const* interfaceDesc;
unsigned char epInAddr = ENDPOINT_BULK_IN;
unsigned char epOutAddr = ENDPOINT_BULK_OUT;
unsigned char idx;
for (i=0;i<PACKET_BULK_LEN; i++)
question[i]=(unsigned char)i;
device = libusb_get_device(handle);
r = libusb_get_active_config_descriptor(device, &config);
if (r < 0)
{
fprintf(stderr, "No active descriptor error %d\n", r);
return r;
}
interfaceDesc = config->interface[0].altsetting;
for(idx = 0; idx < interfaceDesc->bNumEndpoints; idx++)
{
if ((interfaceDesc->endpoint[idx].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK)
{
if ((interfaceDesc->endpoint[idx].bEndpointAddress & LIBUSB_ENDPOINT_IN) == LIBUSB_ENDPOINT_IN)
{
epInAddr = interfaceDesc->endpoint[idx].bEndpointAddress;
}
else
{
epOutAddr = interfaceDesc->endpoint[idx].bEndpointAddress;
}
}
}
r = libusb_bulk_transfer(handle, epOutAddr, question, PACKET_BULK_LEN,
&transferred,TIMEOUT);
if (r < 0)
{
fprintf(stderr, "Bulk write error %d\n", r);
return r;
}
fprintf(stdout, "Wrote %d bytes", r);
r = libusb_bulk_transfer(handle, epInAddr, answer,PACKET_BULK_LEN,
&transferred, TIMEOUT);
if (r < 0)
{
fprintf(stderr, "Bulk read error %d\n", r);
return r;
}
fprintf(stdout, "Read %d bytes", r);
if (transferred < PACKET_BULK_LEN)
{
fprintf(stderr, "Bulk transfer short read (%d)\n", r);
return -1;
}
printf("Bulk Transfer Loop Test Result:\n");
for(i = 0; i < PACKET_BULK_LEN; i++)
{
if(i%8 == 0)
printf("\n");
printf("%02x, %02x; ",question[i],answer[i]);
}
printf("\n\n");
return 0;
}
static int setupAccessory(
const char* manufacturer,
const char* modelName,
const char* description,
const char* version,
const char* uri,
const char* serialNumber)
{
unsigned char ioBuffer[2];
int devVersion;
int r;
r = libusb_control_transfer(
handle, //handle
0xC0, //bmRequestType
51, //bRequest
0, //wValue
0, //wIndex
ioBuffer, //data
2, //wLength
0 //timeout
);
if(r < 0)
{
return-1;
}
devVersion = ioBuffer[1] << 8 | ioBuffer[0];
fprintf(stdout,"Version Code Device: %d\n", devVersion);
sleep(1); //sometimes hangs on the next transfer :(
if ((libusb_control_transfer(handle,0x40,52,0,0,(unsigned char*)manufacturer,strlen(manufacturer)+1,0) < 0) ||
(libusb_control_transfer(handle,0x40,52,0,1,(unsigned char*)modelName,strlen(modelName)+1,0) < 0) ||
(libusb_control_transfer(handle,0x40,52,0,2,(unsigned char*)description,strlen(description)+1,0) < 0) ||
(libusb_control_transfer(handle,0x40,52,0,3,(unsigned char*)version,strlen(version)+1,0) < 0) ||
(libusb_control_transfer(handle,0x40,52,0,4,(unsigned char*)uri,strlen(uri)+1,0) < 0) ||
(libusb_control_transfer(handle,0x40,52,0,5,(unsigned char*)serialNumber,strlen(serialNumber)+1,0) < 0))
{
return -1;
}
fprintf(stdout,"Accessory Identification sent\n", devVersion);
r = libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0);
if(r < 0)
{
return -1;
}
fprintf(stdout,"Attempted to put device into accessory mode\n", devVersion);
return 0;
}
Besides some refactoring and adding the necessary libusb_close(handle) calls mentioned in #ColinM's answer this is mainly adding:
Enumeration over the available end-points
Assumes the device is already in accessory mode if initial PID/VID not found

Categories

Resources