1
0
mirror of https://github.com/nerzhul/ownCloud-SMS-App.git synced 2025-06-07 16:06:18 +00:00

Update tools versions & prepare JNI work to reduce memory & CPU usage

This commit is contained in:
Loic Blot 2017-07-29 14:54:49 +02:00 committed by Loïc Blot
parent c52168c939
commit 47c2923d0e
14 changed files with 465 additions and 25 deletions

View File

@ -23,3 +23,9 @@ android:
- 'google-gdk-license-.+'
- 'android-sdk-preview-license-.+'
- 'android-.*'
before_install:
- wget https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip > /dev/null
- mkdir -p /usr/local/android-sdk/ndk-bundle
- unzip android-ndk-r15c-linux-x86_64.zip -d /usr/local/android-sdk/ndk-bundle > /dev/null
- export ANDROID_NDK_HOME="/usr/local/android-sdk/ndk-bundle/android-ndk-r15c"

13
CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.5.0)
set (SRC_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/httpclient.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/nativesms.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/smsbuffer.cpp
)
find_library(LOGGING_LIBRARY log)
add_library(nativesms SHARED ${SRC_FILES})
target_link_libraries(nativesms ${LOGGING_LIBRARY})

View File

@ -25,6 +25,17 @@ android {
minSdkVersion 16
targetSdkVersion 26
maxSdkVersion 26
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
'arm64-v8a'
}
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions -std=c++11"
}
}
}
buildTypes {
@ -36,6 +47,11 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE.txt'
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
}
repositories {

View File

@ -0,0 +1,56 @@
/**
* Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "httpclient.h"
const char *HTTPClient::classPathName = "fr/unix_experience/owncloud_sms/engine/OCHttpClient";
// See https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html
JNINativeMethod HTTPClient::methods[] =
{
DECL_JNIMETHOD(getAllSmsIdsCall, "()Ljava/lang/String;")
DECL_JNIMETHOD(getLastMsgTimestamp, "()Ljava/lang/String;")
DECL_JNIMETHOD(getPushRoute, "()Ljava/lang/String;")
DECL_JNIMETHOD(getVersionCall, "()Ljava/lang/String;")
};
DECL_METHODSIZE(HTTPClient)
// APIv1 calls
#define RCALL_GET_VERSION "/index.php/apps/ocsms/get/apiversion?format=json"
#define RCALL_GET_ALL_SMS_IDS "/index.php/apps/ocsms/get/smsidlist?format=json"
#define RCALL_GET_LAST_MSG_TIMESTAMP "/index.php/apps/ocsms/get/lastmsgtime?format=json"
#define RCALL_PUSH_ROUTE "/index.php/apps/ocsms/push?format=json"
jstring HTTPClient::getVersionCall(JNIEnv *env, jobject)
{
return env->NewStringUTF(RCALL_GET_VERSION);
}
jstring HTTPClient::getAllSmsIdsCall(JNIEnv *env, jobject)
{
return env->NewStringUTF(RCALL_GET_ALL_SMS_IDS);
}
jstring HTTPClient::getLastMsgTimestamp(JNIEnv *env, jobject)
{
return env->NewStringUTF(RCALL_GET_LAST_MSG_TIMESTAMP);
}
jstring HTTPClient::getPushRoute(JNIEnv *env, jobject)
{
return env->NewStringUTF(RCALL_PUSH_ROUTE);
}

34
src/main/cpp/httpclient.h Normal file
View File

@ -0,0 +1,34 @@
/**
* Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <jni.h>
#include "macro_helpers.h"
class HTTPClient
{
public:
JNIEXPORT static jstring JNICALL getVersionCall(JNIEnv *env, jobject);
JNIEXPORT static jstring JNICALL getAllSmsIdsCall(JNIEnv *env, jobject);
JNIEXPORT static jstring JNICALL getLastMsgTimestamp(JNIEnv *env, jobject);
JNIEXPORT static jstring JNICALL getPushRoute(JNIEnv *env, jobject);
DECL_JNICLASSATTRS
};

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define DECL_JNIMETHOD(name, type) \
{#name, type, (void*) &name },
#define DECL_METHODSIZE(T) \
int T::methods_size = sizeof(T::methods) / sizeof(T::methods[0]);
#define DECL_JNICLASSATTRS \
static const char *classPathName; \
static JNINativeMethod methods[]; \
static int methods_size;

View File

@ -0,0 +1,76 @@
/**
* Copyright (c) 2014-2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <jni.h>
#include <android/log.h>
#include "httpclient.h"
#include "smsbuffer.h"
#define LOG_TAG "nativesms.cpp"
/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = env->FindClass(className);
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Registering class '%s'", className);
if (clazz == NULL) {
__android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "Native registration unable to find class %s", className);
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "RegisterNatives failed for %s", className);
return JNI_FALSE;
}
return JNI_TRUE;
}
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env,
HTTPClient::classPathName,
HTTPClient::methods,
HTTPClient::methods_size)) {
return JNI_FALSE;
}
if (!registerNativeMethods(env,
SmsBuffer::classPathName,
SmsBuffer::methods,
SmsBuffer::methods_size)) {
return JNI_FALSE;
}
return JNI_TRUE;
}
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "NativeSMS library loading...");
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
registerNatives(env);
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "NativeSMS library loaded.");
return JNI_VERSION_1_6;
}

View File

@ -0,0 +1,94 @@
/**
* Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <android/log.h>
#include "smsbuffer.h"
#define LOG_TAG "SmsBuffer"
const char *SmsBuffer::classPathName = "fr/unix_experience/owncloud_sms/jni/SmsBuffer";
// See https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html
JNINativeMethod SmsBuffer::methods[] =
{
DECL_JNIMETHOD(createNativeObject, "()J")
DECL_JNIMETHOD(deleteNativeObject, "(J)V")
DECL_JNIMETHOD(push, "(JI)V")
DECL_JNIMETHOD(print, "(J)V")
};
DECL_METHODSIZE(SmsBuffer)
jlong SmsBuffer::createNativeObject(JNIEnv *env, jobject self)
{
return reinterpret_cast<jlong>(new SmsBuffer());
}
void SmsBuffer::deleteNativeObject(JNIEnv *env, jobject self, jlong ptr)
{
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "deleteSmsBuffer");
delete reinterpret_cast<SmsBuffer *>(ptr);
}
SmsBuffer::SmsBuffer()
{
}
void SmsBuffer::reset_buffer()
{
m_buffer.clear();
m_buffer_empty = true;
}
void SmsBuffer::push(JNIEnv *env, jobject self, jlong ptr, jint mailbox_id)
{
SmsBuffer *me = reinterpret_cast<SmsBuffer *>(ptr);
if (!me) {
__android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "It's not a SmsBuffer!");
return;
}
me->_push(mailbox_id);
}
void SmsBuffer::_push(int mailbox_id)
{
// If buffer is not empty, we are joining messages
if (!m_buffer_empty) {
m_buffer << ",";
}
// Else, we are starting array
else {
m_buffer << "[";
m_buffer_empty = true;
}
m_buffer << "{\"mbox\": " << mailbox_id << "}";
}
void SmsBuffer::print(JNIEnv *env, jobject self, jlong ptr)
{
SmsBuffer *me = reinterpret_cast<SmsBuffer *>(ptr);
if (!me) {
__android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "It's not a SmsBuffer!");
return;
}
me->_print();
}
void SmsBuffer::_print()
{
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "SmsBuffer content: '%s'", m_buffer.str().c_str());
}

44
src/main/cpp/smsbuffer.h Normal file
View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <jni.h>
#include <sstream>
#include "macro_helpers.h"
class SmsBuffer
{
public:
SmsBuffer();
JNIEXPORT static jlong JNICALL createNativeObject(JNIEnv *env, jobject self);
JNIEXPORT static void JNICALL deleteNativeObject(JNIEnv *env, jobject self, jlong ptr);
JNIEXPORT static void JNICALL push(JNIEnv *env, jobject self, jlong ptr, jint mailbox_id);
void _push(int mailbox_id);
JNIEXPORT static void JNICALL print(JNIEnv *env, jobject self, jlong ptr);
void _print();
DECL_JNICLASSATTRS
private:
void reset_buffer();
std::stringstream m_buffer;
bool m_buffer_empty{true};
};

View File

@ -1,7 +1,7 @@
package fr.unix_experience.owncloud_sms.activities;
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* Copyright (c) 2014-2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as

View File

@ -26,6 +26,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import fr.unix_experience.owncloud_sms.enums.MailboxID;
import fr.unix_experience.owncloud_sms.jni.SmsBuffer;
import fr.unix_experience.owncloud_sms.providers.SmsDataProvider;
public class AndroidSmsFetcher {
@ -56,6 +57,9 @@ public class AndroidSmsFetcher {
// Mailbox ID is required by server
entry.put("mbox", mbID.ordinal());
result.put(entry);
SmsBuffer buf = new SmsBuffer();
buf.push(mbID.ordinal());
buf.print();
} catch (JSONException e) {
Log.e(AndroidSmsFetcher.TAG, "JSON Exception when reading SMS Mailbox", e);

View File

@ -27,24 +27,32 @@ import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.httpclient.params.HttpMethodParams;
import java.io.IOException;
import fr.unix_experience.owncloud_sms.providers.AndroidVersionProvider;
public class OCHttpClient extends HttpClient {
static {
System.loadLibrary("nativesms");
}
public static native String getAllSmsIdsCall();
public static native String getLastMsgTimestamp();
public static native String getPushRoute();
public static native String getVersionCall();
private static final String TAG = OCHttpClient.class.getCanonicalName();
private static final String PARAM_PROTOCOL_VERSION = "http.protocol.version";
@ -52,12 +60,6 @@ public class OCHttpClient extends HttpClient {
private final String _username;
private final String _password;
// API v1 calls
private static final String OC_GET_VERSION = "/index.php/apps/ocsms/get/apiversion?format=json";
private static final String OC_GET_ALL_SMS_IDS = "/index.php/apps/ocsms/get/smsidlist?format=json";
private static final String OC_GET_LAST_MSG_TIMESTAMP = "/index.php/apps/ocsms/get/lastmsgtime?format=json";
private static final String OC_PUSH_ROUTE = "/index.php/apps/ocsms/push?format=json";
// API v2 calls
private static final String OC_V2_GET_PHONELIST = "/index.php/apps/ocsms/api/v2/phones/list?format=json";
private static final String OC_V2_GET_MESSAGES ="/index.php/apps/ocsms/api/v2/messages/[START]/[LIMIT]?format=json";
@ -72,7 +74,7 @@ public class OCHttpClient extends HttpClient {
_username = accountName;
_password = accountPassword;
getParams().setParameter(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true);
getParams().setParameter(PARAM_PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
getParams().setParameter(OCHttpClient.PARAM_PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
getParams().setParameter(HttpMethodParams.USER_AGENT,
"nextcloud-phonesync (" + new AndroidVersionProvider(context).getVersionCode() + ")");
@ -84,15 +86,15 @@ public class OCHttpClient extends HttpClient {
}
GetMethod getAllSmsIds() {
return get(OCHttpClient.OC_GET_ALL_SMS_IDS);
return get(OCHttpClient.getAllSmsIdsCall());
}
public GetMethod getVersion() {
return get(OCHttpClient.OC_GET_VERSION);
return get(OCHttpClient.getVersionCall());
}
PostMethod pushSms(StringRequestEntity ent) {
PostMethod post = new PostMethod(_serverURI.toString() + OCHttpClient.OC_PUSH_ROUTE);
PostMethod post = new PostMethod(_serverURI.toString() + OCHttpClient.getPushRoute());
post.setRequestEntity(ent);
return post;
}
@ -109,24 +111,24 @@ public class OCHttpClient extends HttpClient {
private int followRedirections(HttpMethod httpMethod) throws IOException {
int redirectionsCount = 0;
int status = httpMethod.getStatusCode();
while (redirectionsCount < 3 &&
(status == HttpStatus.SC_MOVED_PERMANENTLY ||
status == HttpStatus.SC_MOVED_TEMPORARILY ||
status == HttpStatus.SC_TEMPORARY_REDIRECT)
while ((redirectionsCount < 3) &&
((status == HttpStatus.SC_MOVED_PERMANENTLY) ||
(status == HttpStatus.SC_MOVED_TEMPORARILY) ||
(status == HttpStatus.SC_TEMPORARY_REDIRECT))
) {
Header location = httpMethod.getResponseHeader("Location");
if (location == null) {
location = httpMethod.getResponseHeader("location");
}
if (location == null) {
Log.e(TAG, "No valid location header found when redirecting.");
Log.e(OCHttpClient.TAG, "No valid location header found when redirecting.");
return 500;
}
try {
httpMethod.setURI(new URI(location.getValue()));
} catch (URIException e) {
Log.e(TAG, "Invalid URI in 302 FOUND response");
Log.e(OCHttpClient.TAG, "Invalid URI in 302 FOUND response");
return 500;
}
@ -134,10 +136,10 @@ public class OCHttpClient extends HttpClient {
redirectionsCount++;
}
if (redirectionsCount >= 3 && status == HttpStatus.SC_MOVED_PERMANENTLY ||
status == HttpStatus.SC_MOVED_TEMPORARILY ||
status == HttpStatus.SC_TEMPORARY_REDIRECT) {
Log.e(TAG, "Too many redirection done. Aborting, please ensure your server is " +
if (((redirectionsCount >= 3) && (status == HttpStatus.SC_MOVED_PERMANENTLY)) ||
(status == HttpStatus.SC_MOVED_TEMPORARILY) ||
(status == HttpStatus.SC_TEMPORARY_REDIRECT)) {
Log.e(OCHttpClient.TAG, "Too many redirection done. Aborting, please ensure your server is " +
"correctly configured");
return 400;
}

View File

@ -0,0 +1,49 @@
package fr.unix_experience.owncloud_sms.jni;
/**
* Copyright (c) 2014-2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class SmsBuffer {
static {
System.loadLibrary("nativesms");
}
private long mHandle;
public SmsBuffer() {
mHandle = SmsBuffer.createNativeObject();
}
protected void finalize() throws Throwable {
SmsBuffer.deleteNativeObject(mHandle);
mHandle = 0;
super.finalize();
}
private static native long createNativeObject();
private static native void deleteNativeObject(long handle);
public static native void push(long handle, int mbid);
public void push(int mbid) {
SmsBuffer.push(mHandle, mbid);
}
public static native void print(long handle);
public void print() {
SmsBuffer.print(mHandle);
}
}

View File

@ -1,5 +1,22 @@
package fr.unix_experience.owncloud_sms.notifications;
/*
* Copyright (c) 2014-2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;