This question already has answers here:
java.rmi.NoSuchObjectException: no such object in table
(7 answers)
Closed 7 years ago.
I have a problem with JAVA RMI.
I have a java ee application running, which uses rmi to call specific methods, which have to be implemented specificly for each customer.
The vendor gave me an example RMI interface implementation to show how to get a specific hostinterface running.
The original codefragment looked like posted example1.
The Interface is running but every 2 to 3 days it stops working, without any known reason. The interfaces' log looks like it would be still running.
The glassfish server, which calls the interface, shows log entries like this:
[#|2015-10-01T16:27:53.446+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=106;_ThreadName=Thread-2;|egatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
...
The application error log shows entries like this:
2015-10-05 08:44:07,819 [http-thread-pool-8080(4)] ERROR medexter.arden.server.engine.DelegatingHostInterface - The method evaluateRead on remote interface does not work correctly.
java.rmi.NoSuchObjectException: no such object in table
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
...
I found several threads like this one:
java.rmi.NoSuchObjectException: no such object in table
which tells me the garbage-collection could be responsible and the registry has to be kept statically to prevent the GC from destroying the object.
Meanwhile I tried out diffrent ways. My last one (which somehow shows my desparation - restarting the interface every 24h should not be the golden solution) is posted in example2.
At the moment I generate an executable jar file and start it as an application. I wanted to get it running as a service later on, but first it should work without any mistakes.
Does anybody hava an idea, what the reason for the described behaviour could be?
Any imporovement of the given code apprechiated. I just want to get this stuff working, without loosing connection every few days.
Thank you very much,
Martin
Example 1:
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class SampleRMIProvider {
private static RmiRegistryThread thr;
public static void main(String[] args) {
SampleRMIProvider prv = new SampleRMIProvider();
prv.init();
}
public void init(){
SampleRMIProvider.thr = new RmiRegistryThread();
thr.start();
}
public class RmiRegistryThread extends Thread {
public boolean run = true;
#Override
public void run() {
System.err.println("thread start");
String name = "RMIHostInterface";
int servicePorti = Integer.parseInt("18989");
try {
RmiHostInterface engine = new RmiHostInterfaceImpl();
RmiHostInterface stub = (RmiHostInterface) UnicastRemoteObject.exportObject(engine, 0);
Registry registry;
try {
registry = LocateRegistry.createRegistry(servicePorti);
} catch (RemoteException e) {
registry = LocateRegistry.getRegistry(servicePorti);
}
registry.bind(name, stub);
} catch (RemoteException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
e.printStackTrace();
}
try {
while (this.run) {
Thread.sleep(10000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Example 2:
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class SampleRMIProvider extends Thread{
private static Registry r = null;
#Override
public void run() {
String name = "RMIHostInterface";
int servicePorti = Integer.parseInt("20002"); //18989
try {
RmiHostInterface engine = new SampleInterfaceImpl();
RmiHostInterface stub = (RmiHostInterface) UnicastRemoteObject.exportObject(engine, 0);
try {
SampleRMIProvider.r = LocateRegistry.createRegistry(servicePorti);
} catch (RemoteException e) {
SampleRMIProvider.r = LocateRegistry.getRegistry(servicePorti);
}
SampleRMIProvider.r.bind(name, stub);
} catch (RemoteException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
e.printStackTrace();
}
System.err.println("RMI Interface created...");
try{
while(true){
Thread.sleep(10000);
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
while (true) {
//RMI Interface instanzieren
SampleRMIProvider provider = new SampleRMIProvider();
provider.start();
//Ein Tag pause
Thread.sleep(86400000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
14.10.2015
Finally - this minimal example shows a solution that worked for me. Thanks for the useful advices.
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class SampleRMIProvider{
private static Registry r = null;
private static SampleHostInterfaceImpl hif = null;
private static RmiHostInterface stub = null;
SampleRMIProvider(){
try{
SampleRMIProvider.r.bind("RMIHostInterface", SampleRMIProvider.stub);
}
catch(RemoteException | AlreadyBoundException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
//setup static references to prevent from beeing collected by GC
try {
SampleRMIProvider.hif = new SampleHostInterfaceImpl();
SampleRMIProvider.stub = (RmiHostInterface) UnicastRemoteObject.exportObject(SampleRMIProvider.hif, 0);
try {
SampleRMIProvider.r = LocateRegistry.createRegistry(20002);
} catch (RemoteException e) {
SampleRMIProvider.r = LocateRegistry.getRegistry(20002);
}
} catch (RemoteException e) {
e.printStackTrace();
}
new SampleRMIProvider();
}
}
I don't know what you mean by 'no known cause', when the cause is documented in the Javadoc of the exception.
You say that you've read that the Registry reference must be static, yet you don't have a static Registry reference anywhere.
Try implementing that.
Related
I'm making a chat with rmi in Java. I have one server object and at least two clients objects. When a client send a message to the server calling the method recebeMensagem remotely, the server must print that message on all clients' screen (except the client that sent the message).
The client class has a method printMenssagem(Mensagem msg), that is called remotely by the server. The problem is that that method is printing on server's screen. How do I make to print the message on client's screen instead?
Server.java:
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.function.Predicate;
public class Server implements ChatServer {
private ArrayList<String> listaClientes = new ArrayList<>();
private static int port = 5002;
public static void main(String[] args) {
try {
Server obj = new Server();
ChatServer stub = (ChatServer)
UnicastRemoteObject.exportObject(obj, port);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.createRegistry(port);
registry.bind("chat", stub);
System.out.println("Server ready!");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
#Override
public void adicionaCliente(String user) {
this.listaClientes.add(user);
}
#Override
public void retiraCliente(String userName) {
Predicate<String> clientePredicate = cp ->
cp.equals(userName);
listaClientes.removeIf(clientePredicate);
try {
Registry registry = LocateRegistry.getRegistry(port);
registry.unbind(userName);
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
#Override
public void recebeMensagem(Mensagem msg) {
try {
Registry registry = LocateRegistry.getRegistry(port);
for(String cliente : listaClientes) {
if (!cliente.equals(msg.getRemetente())) {
Client stub = (Client) registry.lookup(cliente);
stub.printMensagem(msg);
}
}
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
public ArrayList<String> getListaClientes() {
return listaClientes;
}
public void setListaClientes(ArrayList<String> listaClientes) {
this.listaClientes = listaClientes;
}
}
Client.java :
import java.io.Serializable;
import java.rmi.Remote;
public class Client implements Remote, Serializable {
private static final long serialVersionUID = 6864579049922061838L;
private static int port = 5002;
private static String host = "127.0.0.1";
public static void main(String[] args) {
new Thread(new ClientInterface(host, port)).start();
}
public void printMensagem(Mensagem mensagem) {
System.out.println(mensagem.getRemetente() + ": " + mensagem.getMensagem());
}
}
how to make client stub method called on server print message on client screen?
The client doesn't have a stub. It isn't a remote object. It is a serializable object and it has been transported to the Registry holus bolus, and it runs in whatever JVM performed the Registry.lookup() to obtain it. This is not what you want. You want it to be a remote object, with a stub, so you have to make it implement a remote interface, and export it, and use it via its remote interface at the peer.
You also need to be aware that your present architecture won't work across more than one host, as you can't bind to a remote Registry. You will need to add a client registration method to the server.
I have create a File watcher using org.apache.commons.io.monitor.FileAlterationMonitor. The file changes are captured correctly. But I want to stop the monitor task using a separate method. Its not working. The source code is as below.
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import org.apache.commons.io.FileDeleteStrategy;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.apache.commons.io.monitor.FileEntry;
public class FileMonitor2 {
//public final class FileMonitorExample {
private static final String EXAMPLE_PATH =
"D:\\testrail\\install.txt";
private static final String PARENT_DIR1 =
"D:\\ibi\\DevStudio77\\client\\wfc\\etc";
private static final String PARENT_DIR2 =
"D:\\ibi\\DevStudio77\\config";
public static void runExample(boolean b) {
System.out.println("File Monitor example...");
FileAlterationMonitor monitor=new FileAlterationMonitor();
// FileEntry
// We can monitor changes and get information about files
// using the methods of this class.
if(b){
FileEntry entry = new FileEntry(FileUtils.getFile(EXAMPLE_PATH));
System.out.println("File monitored: " + entry.getFile());
System.out.println("File name: " + entry.getName());
System.out.println("Is the file a directory?: " + entry.isDirectory());
// File Monitoring
// Create a new observer for the folder and add a listener
// that will handle the events in a specific directory and take action.
File parentDir = FileUtils.getFile(PARENT_DIR1);
FileAlterationObserver observer = new FileAlterationObserver(parentDir);
observer.addListener(new FLA2());
File parentDir1 = FileUtils.getFile(PARENT_DIR2);
FileAlterationObserver observer2 = new FileAlterationObserver(parentDir1);
// observer.addListener(new FLA());
observer2.addListener(new FLA());
// Add a monior that will check for events every x ms,
// and attach all the different observers that we want.
monitor.addObserver(observer);
//monitor = new FileAlterationMonitor(500, observer);
monitor.addObserver(observer2);
try {
monitor.start();
System.out.println("Started");
// After we attached the monitor, we can create some files and directories
// and see what happens!
//monitor.stop();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}else{
/*System.out.println("type the value");
Scanner sc=new Scanner(System.in);
String ss=sc.next();
if(ss.equals("aa")){*/
try {
monitor.stop();
System.out.println("stopped");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// }
}
}
public static void main(String args[]) throws InterruptedException{
runExample(true);
System.out.println("After start");
Thread.sleep(1000);
runExample(false);
}
//}
}
When runExample(false) is called the second time, the monitor is recreated. You need to called monitor.stop() on the instance which was created when you called runExample(true). You can save the monitor to a static variable after it is created the first time. Any subsequent calls to runExample(false) then has access to the original instance of monitor.
You can fix this by declaring monitor outside of the runExample method, and only create a new monitor if true was passed:
static FileAlterationMonitor monitor;
public static void runExample(boolean b) {
if (b) {
monitor = new FileAlterationMonitor();
} else {
if (monitor == null) return;
monitor.stop();
}
}
I want to capture an AXIS camera & stream it. I am quite new to RED5. I get the following error:
Exception in thread "main" java.lang.NullPointerException at
org.vikulin.rtmp.publisher.Publisher2.packetReceived(Publisher2.java:23)
at
org.red5.server.presentation.output.flv.FLVStream.dispatchEvent(FLVStream.java:243)
at
org.red5.server.presentation.output.flv.FLVStream.sendAVCDecoderConfig(FLVStream.java:162)
at
org.red5.server.presentation.output.flv.FLVStream.addEvent(FLVStream.java:76) at
org.red5.server.presentation.MediaPresentation.onMediaEvent(MediaPresentation.java:43)
at
org.red5.server.presentation.input.avp.codecs.H264.addPacket(H264.java:206)
at
org.red5.server.presentation.RTSPStream.onRTSPEvent(RTSPStream.java:100)
at
org.red5.server.net.rtsp.proxy.RtspTcp.setupAndPlay(RtspTcp.java:287)
at org.red5.server.presentation.RTSPStream.onSDP(RTSPStream.java:138)
at
org.red5.server.net.rtsp.proxy.RtspTcp.parseDescription(RtspTcp.java:128)
at org.red5.server.net.rtsp.proxy.RtspTcp.describe(RtspTcp.java:64)
at
org.red5.server.presentation.RTSPStream.startInput(RTSPStream.java:77)
at org.red5.server.presentation.RTSPStream.start(RTSPStream.java:82)
at org.vikulin.rtmp.publisher.Publisher2.main(Publisher2.java:49)
Here is the code:
import java.io.IOException;
import org.red5.server.api.stream.IBroadcastStream;
import org.red5.server.api.stream.IStreamListener;
import org.red5.server.api.stream.IStreamPacket;
import org.red5.server.net.rtmp.event.VideoData;
import org.red5.server.presentation.RTSPStream;
import org.red5.server.stream.message.RTMPMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Publisher2 implements IStreamListener {
PublishClient client;
#Override
public void packetReceived(IBroadcastStream arg0, IStreamPacket arg1) {
System.out.println("" + arg1);
VideoData data = new VideoData(arg1.getData());
RTMPMessage message = RTMPMessage.build(data);
try {
client.pushMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException, InterruptedException {
Logger log = LoggerFactory.getLogger(Publisher2.class);
String publishName = "testb";
String host = "127.0.0.1";
int port = 1935;
String app = "live";
PublishClient client = new PublishClient();
client.setHost(host);
client.setPort(port);
client.setApp(app);
client.start(publishName, "live", null);
while (client.getState() != PublishClient.PUBLISHED) {
Thread.sleep(500);
}
Publisher2 test = new Publisher2();
final RTSPStream camera = new RTSPStream("192.168.254.115", 554,
"rtsp://192.168.254.115/axis-media/media.amp?videocodec=h264&videokeyframeinterval=30&fps=30");
camera.addStreamListener(test);
new Thread(new Runnable() {
#Override
public void run() {
camera.start();
}
}).start();
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
camera.stop();
try {//wait for write out.
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
client.stop();
}
}
If you have any idea please help me!
You declared a client variable in your main method, but in your packetReceived method, you reference the class variable. The class variable is still null at that point. So, possibly change this line:
PublishClient client = new PublishClient();
to this:
client = new PublishClient();
or pass the client in to your method, and remove variable declaration from your class.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
i try to program a part of a university research project about multi client - server socket programming.my code works as well as so that i give valide result but the problem is that evalutor of our group said that my code have not a good speed on connection for data transfer.i will be thankfull if you found the problem(s) in my code that cause this issue.
server part:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import j
ava.io.PrintStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
/**
*
*/
/**
* #author Sina
*
*/
public class BoxServer {
ServerSocket serversocket;
static ThreadHandler t[]=new ThreadHandler[100];
static int size=0;
static ArrayList<Message> messagebox=new ArrayList<Message>();
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(79);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while(true)
{
try{
//InetAddress inetadress=InetAddress.getLocalHost();
//System.out.println(inetadress);
//System.out.println(inetadress.getHostName());
//System.out.println(inetadress.getHostAddress());
Socket socket=serverSocket.accept();
if(socket==null)
{
System.out.println("null");
}
t[size]=new ThreadHandler(socket,"username");
size++;
t[size-1].start();
}
catch(UnknownHostException e){
System.out.println("salam s");
System.out.println(e.getMessage());
}
catch (IOException e) {
System.out.println("bye s");
System.out.println(e.getMessage());
}
}
}
}
class ThreadHandler extends Thread{
private String socname;
Socket mySocket;
ObjectInputStream inp;
ObjectOutputStream outp;
public ThreadHandler(Socket s,String socketName)
{
this.mySocket=s;
this.socname=socketName;
}
public void run()
{
try {
inp=new ObjectInputStream(mySocket.getInputStream());
outp=new ObjectOutputStream(mySocket.getOutputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while(true)
{
System.out.println("thread run");
System.out.println(mySocket.getLocalPort());
System.out.println(mySocket.getLocalAddress());
try {
// System.out.println("my socket:"+mySocket.getOutputStream());
System.out.println(mySocket.isConnected());
System.out.println(inp.available());
System.out.println("inp = "+inp);
System.out.println("reeead "+ inp.readObject());
Message mess=(Message)inp.readObject();
System.out.println("dsd");
System.out.println("mess: "+mess);
BoxServer.messagebox.add(mess);
if(mess.getReceiver().equals("system-use:code=1"))
{
System.out.println(mess.getSender()+" wants to see his/her Inbox");
}
//mySocket.close();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("bug dar thread");
e.printStackTrace();
}
}
}
}
client part
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import javax.swing.Timer;
public class Main {
/**
* #param args
*/
static Socket socket=new Socket();
public static void main(String[] args) {
System.out.println("newuser(n) or login(l)");
Scanner scanner=new Scanner(System.in);
String typeOfOperation=scanner.nextLine();
if(typeOfOperation.equals("n"))
{
}
else
if(typeOfOperation.equals("l"))
{
try {
socket = new Socket("127.0.0.1",79);
final ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in=new ObjectInputStream(socket.getInputStream());
while(true)
{
Thread timer=new Thread()
{
public void run()
{
while(true)
{
Message temp=new Message();
temp.setReceiver("system-use:code=1");
temp.setSender("username");
try {
out.writeObject(temp);
sleep(5000);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
};
timer.start();
String username=scanner.nextLine();
String to=scanner.nextLine();
String body=scanner.nextLine();
Message all=new Message();
all.setText(body);
all.setReceiver(to);
all.setSender(username);
System.out.println("you connected to system");
System.out.println(socket);
System.out.println("now should write");
out.writeObject(all);
System.out.println("ghable threAD");
}
// socket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
System.out.println("salaam c");
System.out.println(e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("bye c");
System.out.println(e.getMessage());
}
}
else
{
System.out.println("bad operation. try again!");
}
}
}
Message class(Entity only not important i think!):
import java.io.Serializable;
public class Message implements Serializable{
String sender;
String receiver;
String text;
boolean delivered=false;
public void delived()
{
this.delivered=true;
}
private String tostringOfClass;
public void setReceiver(String receiver) {
this.receiver = receiver;
}
public void setSender(String sender) {
this.sender = sender;
}
public void setText(String text) {
this.text = text;
}
public String getReceiver() {
return receiver;
}
public String getSender() {
return sender;
}
public String getText() {
return text;
}
public String toString()
{
tostringOfClass="sender : "+sender+" \n"+"receiver : "+receiver+" \n"+"message: "+text;
return tostringOfClass;
}
}
Your evaluator missed something much more important: it doesn't work. You are calling readObject() twice per loop in the server, but all you do with the first result is print it out with System.out.println(). So your code is missing every odd object.
There isn't much you could do to improve the speed of this. He probably wants you to interpose a BufferedOutputStream between the ObjectOutputStream and the socket, and similarly for BufferedInputStream. However the object streams already run their own buffers, so this is probably a waste of time. He might also want you to use large socket send and receive buffers, if you've been taught about those: see Socket.setXXXBufferSize(). Set them to at least 32k. He might also be anti-Serialization, but for this application I don't see that it makes much difference. This is an interactive application, and the messages are small, so the speed over the network is basically irrelevant. You can only type so fast.
You should also close in the client when the user types whatever it is that tells the program to stop, and in the server you must catch EOFException, before IOException, and close the socket and break out of the read loop when you get it.
Also printing out Socket.isConnected() yields no useful information. The socket is always connected at the points you print it at. This method is not a health-check for the connection, it only tells you about the state of your Socket. Not the same thing.
Your evaluator seems to me to be focussing on entirely the wrong thing.
I'm not sure how much time you would want to invest in optimizing your Socket code, but ZMQ http://www.zeromq.org/ has helped greatly in removing latency and optimizing the Bandwidth usage.
However, in simpler notes. Try not to use ObjectOutputStream they are one layer above. Go immediately for DataInputStream and DataOutputStream (Maybe also BufferedInputStream) It's been a while for me, so I'm rusty. But since you are sending strings, you don't need to do Object Serialization along with it.
You said, your time is being lost in data transfer as well. But consider not creating a new thread on each connection and use thread pools.
and Salam.
I want to write some bytes to a shared memory. This is done in my application1. From my another application: application2 I want to access that shared memory to read the written bytes. For this purpose I tried using android's MemoryFile class. I am stuck as how to refer to the same shard memory between two different application. I am also now confused if memoryFile is used for the same purpose or not.
http://developer.android.com/reference/android/os/MemoryFile.html this link I found regarding the topic.
Thanks in advance.
Krishna
If you want some cross-process use with MemoryFile you can use the following fugly method:
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import java.io.FileDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MemoryFileUtil {
private static final Method sMethodGetParcelFileDescriptor;
private static final Method sMethodGetFileDescriptor;
static {
sMethodGetParcelFileDescriptor = get("getParcelFileDescriptor");
sMethodGetFileDescriptor = get("getFileDescriptor");
}
public static ParcelFileDescriptor getParcelFileDescriptor(MemoryFile file) {
try {
return (ParcelFileDescriptor) sMethodGetParcelFileDescriptor.invoke(file);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
public static FileDescriptor getFileDescriptor(MemoryFile file) {
try {
return (FileDescriptor) sMethodGetFileDescriptor.invoke(file);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private static Method get(String name) {
try {
return MemoryFile.class.getDeclaredMethod(name);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
What you should be looking at is the #getParcelFileDescriptor(MemoryFile) method which you can return from an implementation of ContentProvider#openFile(Uri, String).
I suspect memory files don't have the getParcelFileDescriptor method. When I commented this getParcelFileDescriptor related methods and use getFileDescriptor. It worked nicely.
import java.io.FileDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.os.MemoryFile;
/**
* Invoke hidden methods using reflection
*
*/
public class MemoryFileUtil {
private static final Method sMethodGetFileDescriptor;
static {
sMethodGetFileDescriptor = get("getFileDescriptor");
}
public static FileDescriptor getFileDescriptor(MemoryFile file) {
try {
return (FileDescriptor) sMethodGetFileDescriptor.invoke(file);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private static Method get(String name) {
try {
return MemoryFile.class.getDeclaredMethod(name);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
And created File descriptor from memory file.
FileDescriptor fd = MemoryFileUtil.getFileDescriptor(memFile);
MemoryFile can be used to map to physical memory. The result file descriptor (fd) can be passed to client (memory sharing side). The client can map the same native fd to the same memory region. The memory can then be shared using the native fd, which can be mapped to java layer using InputStream.
Please refer to this link for more details:
Sharing memory using ashem.