diff --git a/penguinpeak/Android.mk b/penguinpeak/Android.mk
new file mode 100644
index 0000000..fcc6a9c
--- /dev/null
+++ b/penguinpeak/Android.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+# Copyright (C) 2021 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(my-dir)
+include $(call all-subdir-makefiles, $(LOCAL_PATH))
diff --git a/penguinpeak/ClipboardAgent/Android.bp b/penguinpeak/ClipboardAgent/Android.bp
new file mode 100644
index 0000000..9157286
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+// Copyright (C) 2021 Intel Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// This makefile shows how to build a shared library and an activity that
+// bundles the shared library and calls it using JNI.
+
+android_app {
+ name: "ClipboardAgent",
+ srcs: ["**/*.java"],
+ // JNI library built from C++ source code
+ jni_libs: ["libVsockMsgDispatch", "libVsocketClientImpl"],
+ optimize: {
+ enabled: false,
+ },
+ sdk_version: "system_current",
+ dex_preopt: {
+ enabled: false,
+ },
+ privileged: true,
+ // To match the signature
+ certificate: "platform",
+}
diff --git a/penguinpeak/ClipboardAgent/AndroidManifest.xml b/penguinpeak/ClipboardAgent/AndroidManifest.xml
new file mode 100644
index 0000000..3764a52
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/AndroidManifest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/penguinpeak/ClipboardAgent/jni/Android.bp b/penguinpeak/ClipboardAgent/jni/Android.bp
new file mode 100644
index 0000000..52c086e
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/Android.bp
@@ -0,0 +1,139 @@
+//
+// Copyright (C) 2008 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// This makefile supplies the rules for building a library of JNI code for
+// use by our example of how to bundle a shared library with an APK.
+
+cc_library_shared {
+ name: "libVsocketClientImpl",
+ // All of the source files that we will compile.
+ srcs: ["VsockClientImpl.cpp"],
+ // All of the shared libraries we link against.
+ // liblog is used to print trace log in C plus plus source code.
+ shared_libs: ["liblog"],
+ // No static libraries.
+ static_libs: [],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ // We cannot use stl:"none" here to link libc++ dynamically because
+ // it caused "'iostream' file not found" build issue.
+ stl: "c++_static",
+ sdk_version: "current",
+}
+
+genrule {
+ name: "pgp-proto",
+ tool_files: [ ":TAF-proto-gen", ":TAF-templates", ":TAF-proto-gen-deps",],
+ srcs: [
+ "proto/appstatus-protogen.inp",
+ "proto/notification-protogen.inp",
+ ],
+ out: [
+ "proto/appstatus-gen.proto",
+ "proto/notification-gen.proto",
+ ],
+ cmd: "$(location) -I vendor/intel/external/apps/penguinpeak/ClipboardAgent/jni/ -o $(genDir) -i $(in) --proto",
+}
+
+genrule {
+ name: "pgp-headers",
+ tool_files: [ ":TAF-proto-gen", ":TAF-templates", ":TAF-proto-gen-deps",],
+ srcs: [
+ "proto/appstatus-protogen.inp",
+ "proto/notification-protogen.inp",
+ ],
+ out: [
+ "proto/appstatus.h",
+ "proto/notification.h",
+ ],
+ cmd: "$(location) -I vendor/intel/external/apps/penguinpeak/ClipboardAgent/jni/ -o $(genDir) -i $(in) --header",
+}
+
+
+genrule {
+ name: "pgp-gRPCGenStub_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Iout/soong/.intermediates/vendor/intel/external/apps/penguinpeak/ClipboardAgent/jni/pgp-proto/gen -Ivendor/intel/external/apps/penguinpeak/ClipboardAgent/jni -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [ ":pgp-proto",
+ "proto/appstatus.proto",
+ "proto/notification.proto",
+ ],
+ out: [
+ "proto/appstatus.pb.h",
+ "proto/appstatus-gen.pb.h",
+ "proto/appstatus-gen.grpc.pb.h",
+ "proto/notification.pb.h",
+ "proto/notification-gen.pb.h",
+ "proto/notification-gen.grpc.pb.h",
+ ],
+}
+
+genrule {
+ name: "pgp-gRPCGenStub_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Iout/soong/.intermediates/vendor/intel/external/apps/penguinpeak/ClipboardAgent/jni/pgp-proto/gen -Ivendor/intel/external/apps/penguinpeak/ClipboardAgent/jni -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":pgp-proto",
+ "proto/appstatus.proto",
+ "proto/notification.proto",
+ ],
+ out: [
+ "proto/appstatus.pb.cc",
+ "proto/appstatus-gen.pb.cc",
+ "proto/appstatus-gen.grpc.pb.cc",
+ "proto/notification.pb.cc",
+ "proto/notification-gen.pb.cc",
+ "proto/notification-gen.grpc.pb.cc",
+ ],
+}
+
+cc_library_shared {
+ name: "libVsockMsgDispatch",
+ defaults: ["TAF-defaults",],
+ srcs: [
+ "DispatchHelper.cpp",
+ "adapter.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-unused-label",
+ ],
+ generated_headers: [ "pgp-headers", "pgp-gRPCGenStub_h", ],
+ generated_sources: [ "pgp-gRPCGenStub_cc", ],
+ sdk_version: "current",
+}
+
+cc_binary {
+ name: "cfc_host_agent",
+ host_supported: true,
+ defaults: ["TAF-defaults",],
+ srcs: [
+ "appstatus.cpp",
+ "notification.cpp",
+ ],
+ generated_headers: [ "pgp-headers", "pgp-gRPCGenStub_h", ],
+ generated_sources: [ "pgp-gRPCGenStub_cc", ],
+}
diff --git a/penguinpeak/ClipboardAgent/jni/DispatchHelper.cpp b/penguinpeak/ClipboardAgent/jni/DispatchHelper.cpp
new file mode 100644
index 0000000..bc41fea
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/DispatchHelper.cpp
@@ -0,0 +1,44 @@
+#include "DispatchHelper.h"
+#include
+#include
+#include "adapter.h"
+
+#undef LOG_TAG
+#define LOG_TAG "DispatchHelper"
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_DispatchHelper_registerComponent(JNIEnv *env, jobject thisObject, jstring className) {
+ env->GetJavaVM(&gVm);
+ std::string name = env->GetStringUTFChars(className, 0);
+ LOG_INFO("Attempting to register Service %s\n", name.c_str());
+ ServiceAdapter* adapter = AdapterFactory::GetAdapter(name);
+ if (adapter != nullptr) {
+ adapter->Register();
+ } else {
+ LOG_ERROR("Service adapter not found for %s\n", name.c_str());
+ }
+}
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_DispatchHelper_sendMsg(JNIEnv *env, jobject thisObject, jstring className, jobject msg, jlong handle) {
+ JavaObjectHelper jobjHelper(msg);
+ std::string name = env->GetStringUTFChars(className, 0);
+ ServiceAdapter* adapter = AdapterFactory::GetAdapter(name);
+ if (adapter == nullptr) {
+ LOG_ERROR("Service adapter not found for %s\n", name.c_str());
+ return;
+ }
+ adapter->SendResponse(&jobjHelper);
+}
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_DispatchHelper_start(JNIEnv *env, jobject thisObject) {
+ if (!g_server_->Start()) {
+ LOG_ERROR("FATAL! Failed to start server");
+ }
+}
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_DispatchHelper_stop(JNIEnv *env, jobject thisObject) {
+ g_server_->Stop();
+ delete g_server_;
+ g_server_ = nullptr;
+ AdapterFactory::RemoveAll();
+}
+
diff --git a/penguinpeak/ClipboardAgent/jni/DispatchHelper.h b/penguinpeak/ClipboardAgent/jni/DispatchHelper.h
new file mode 100644
index 0000000..4b9708b
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/DispatchHelper.h
@@ -0,0 +1,45 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class com_intel_clipboardagent_DispatchHelper */
+
+#ifndef _Included_com_intel_clipboardagent_DispatchHelper
+#define _Included_com_intel_clipboardagent_DispatchHelper
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_intel_clipboardagent_DispatchHelper
+ * Method: registerComponent
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_DispatchHelper_registerComponent
+ (JNIEnv *, jobject, jstring);
+
+/*
+ * Class: com_intel_clipboardagent_DispatchHelper
+ * Method: sendMsg
+ * Signature: (Ljava/lang/String;Ljava/lang/Object;J)V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_DispatchHelper_sendMsg
+ (JNIEnv *, jobject, jstring, jobject, jlong);
+
+/*
+ * Class: com_intel_clipboardagent_DispatchHelper
+ * Method: start
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_DispatchHelper_start
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_intel_clipboardagent_DispatchHelper
+ * Method: stop
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_DispatchHelper_stop
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/penguinpeak/ClipboardAgent/jni/VsockClientImpl.cpp b/penguinpeak/ClipboardAgent/jni/VsockClientImpl.cpp
new file mode 100644
index 0000000..11c0ce7
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/VsockClientImpl.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2021 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#define JVM_IO_INTR (-2)
+#ifndef bufferFER_LEN
+#define bufferFER_LEN 65536
+#endif
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define LOG_TAG "vsock"
+#include
+
+#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
+#define DATA_SIZE_LENGTH 4
+#define MAX_CHUNK_LENGTH 8192
+#define MAX_DATA_LENGTH 512*1024
+
+static const char *vsockClientImplPath = "com/intel/clipboardagent/VsockClientImpl";
+static const char *vsockAddressPath = "com/intel/clipboardagent/VsockAddress";
+static const char *javaConnException = "java/net/ConnectException";
+static const char *javaIntrIOException = "java/io/InterruptedIOException";
+static const char *sunConnResetException = "sun/net/ConnectionResetException";
+
+int read_from_vsock(JNIEnv* env, int sockfd, uint8_t* bytes, uint32_t size) {
+ int nread = (jint) recv(sockfd, bytes, size, 0);
+ if (nread <= 0) {
+ if (nread < 0 && errno != ENOTCONN) {
+ env->ThrowNew(env->FindClass(javaConnException),
+ ("vsock read: Read failed with error no: " + std::to_string(errno)).c_str());
+ } else {
+ env->ThrowNew(env->FindClass(javaConnException),
+ ("vsock read: Connection is closed by peer."));
+ }
+ return nread;
+ }
+ return nread;
+}
+
+bool write_to_vsock(JNIEnv* env, int sockfd, uint8_t* bytes, uint32_t size) {
+ int n = (int)send(sockfd, bytes, size, 0);
+ if (n == JVM_IO_INTR) {
+ env->ThrowNew(env->FindClass(javaIntrIOException), 0);
+ } else if (n <= 0){
+ if (errno == ECONNRESET) {
+ env->ThrowNew(env->FindClass(sunConnResetException), "vsock write: Connection reset");
+ } else {
+ env->ThrowNew(env->FindClass(javaConnException), "vsock write: Write failed");
+ }
+ return false;
+ } else if (n != size) {
+ env->ThrowNew(env->FindClass(javaConnException), "vsock write: Failed to write complete msg");
+ return false;
+ }
+ return true;
+}
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_socketCreate
+ (JNIEnv *env, jobject thisObject) {
+ int sock = socket(AF_VSOCK, SOCK_STREAM, 0);
+
+ jclass implement = env->FindClass(vsockClientImplPath);
+ jfieldID fdField = env->GetFieldID(implement, "fd", "I");
+ env->SetIntField(thisObject, fdField, sock);
+}
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_connect
+ (JNIEnv *env, jobject thisObject, jobject addr) {
+ jclass implement = env->FindClass(vsockClientImplPath);
+ jfieldID fdField = env->GetFieldID(implement, "fd", "I");
+ int sock = (int)env->GetIntField(thisObject, fdField);
+
+ if (sock == -1) {
+ env->ThrowNew(env->FindClass(javaConnException), "vsock: Socket is closed");
+ return;
+ }
+
+ jclass vsockAddress = env->FindClass(vsockAddressPath);
+ jfieldID cidField = env->GetFieldID(vsockAddress, "cid", "I");
+ jfieldID portField = env->GetFieldID(vsockAddress, "port", "I");
+
+
+ struct sockaddr_vm sock_addr;
+ std::memset(&sock_addr, 0, sizeof(struct sockaddr_vm));
+ sock_addr.svm_family = AF_VSOCK;
+ sock_addr.svm_port = (int)env->GetIntField(addr, portField);
+ sock_addr.svm_cid = (int)env->GetIntField(addr, cidField);
+ int status = connect(sock, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr_vm));
+ if (status != 0) {
+ if (errno == EALREADY || errno == EISCONN ) {
+ env->ThrowNew(env->FindClass(javaConnException),
+ ("Connect failed: " + std::to_string(errno)).c_str());
+ }
+ }
+}
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_close
+ (JNIEnv *env, jobject thisObject) {
+ jclass implement = env->FindClass(vsockClientImplPath);
+ jfieldID fdField = env->GetFieldID(implement, "fd", "I");
+ int s = (int)env->GetIntField(thisObject, fdField);
+
+ if (s == -1) {
+ env->ThrowNew(env->FindClass(javaConnException), "vsock close: Socket is already closed.");
+ return;
+ }
+
+ int status = close(s);
+
+ env->SetIntField(thisObject, fdField, -1);
+ if (status != 0) {
+ env->ThrowNew(env->FindClass(javaConnException),
+ ("Close failed: " + std::to_string(errno)).c_str());
+ }
+}
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_write
+ (JNIEnv * env, jobject thisObject, jbyteArray b, jint offset, jint len) {
+ jclass implement = env->FindClass(vsockClientImplPath);
+ jfieldID fdField = env->GetFieldID(implement, "fd", "I");
+ int s = (int)env->GetIntField(thisObject, fdField);
+
+ if (s == -1) {
+ env->ThrowNew(env->FindClass(javaConnException), "vsock write: Socket is already closed.");
+ return;
+ }
+
+
+ // Send the actual data
+ char buffer[MAX_CHUNK_LENGTH];
+ while(len > 0) {
+ int chunkLen = min(MAX_CHUNK_LENGTH, len);
+
+ env->GetByteArrayRegion(b, offset, chunkLen, (jbyte *)buffer);
+ if(!write_to_vsock(env, s, (uint8_t*)buffer, chunkLen)) {
+ return;
+ }
+ len -= chunkLen;
+ offset += chunkLen;
+ }
+ return;
+}
+
+JNIEXPORT jint JNICALL Java_com_intel_clipboardagent_VsockClientImpl_read
+ (JNIEnv * env, jobject thisObject, jbyteArray b, jint off, jint len) {
+ jclass implement = env->FindClass(vsockClientImplPath);
+ jfieldID fdField = env->GetFieldID(implement, "fd", "I");
+ int s = (int)env->GetIntField(thisObject, fdField);
+
+ if (s == -1) {
+ env->ThrowNew(env->FindClass(javaConnException), "vsock read: Socket is already closed");
+ return -1;
+ }
+ uint8_t buffer[MAX_CHUNK_LENGTH];
+ uint32_t remaining = len;
+ while (remaining > 0) {
+ int nread = 0;
+ uint32_t chunkLen = min(remaining, MAX_CHUNK_LENGTH);
+ if ((nread = read_from_vsock(env, s, buffer, chunkLen)) <= 0) {
+ ALOGE("vsock read: Failed to read complete msg");
+ }
+ env->SetByteArrayRegion(b, off, nread, (jbyte *)buffer);
+ remaining -= nread;
+ off += nread;
+ }
+
+ return (jint)len;
+}
+
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_writeInt
+ (JNIEnv *env, jobject thisObject, jint length) {
+ jclass implement = env->FindClass(vsockClientImplPath);
+ jfieldID fdField = env->GetFieldID(implement, "fd", "I");
+ int s = (int)env->GetIntField(thisObject, fdField);
+
+ if (s == -1) {
+ env->ThrowNew(env->FindClass(javaConnException), "vsock read: Socket is already closed");
+ return;
+ }
+
+ {
+ uint32_t size = length;
+ size = htonl(size);
+ uint8_t* buffer = (uint8_t*)&size;
+ if (!write_to_vsock(env, s, buffer, DATA_SIZE_LENGTH)) {
+ return;
+ }
+ }
+}
+
+
+JNIEXPORT jint JNICALL Java_com_intel_clipboardagent_VsockClientImpl_readInt
+ (JNIEnv *env, jobject thisObject) {
+ jclass implement = env->FindClass(vsockClientImplPath);
+ jfieldID fdField = env->GetFieldID(implement, "fd", "I");
+ int s = (int)env->GetIntField(thisObject, fdField);
+
+ if (s == -1) {
+ env->ThrowNew(env->FindClass(javaConnException), "vsock read: Socket is already closed");
+ return -1;
+ }
+
+ uint32_t size = 0;
+ {
+ uint8_t buffer[DATA_SIZE_LENGTH + 1] = {0};
+ if (read_from_vsock(env, s, buffer, DATA_SIZE_LENGTH) != DATA_SIZE_LENGTH) {
+ ALOGE("vsock read: Failed to read data size.");
+ return -1;
+ }
+ size = *(uint32_t*)buffer;
+ size = ntohl(size);
+ }
+ return (jint)size;
+}
diff --git a/penguinpeak/ClipboardAgent/jni/VsockClientImpl.h b/penguinpeak/ClipboardAgent/jni/VsockClientImpl.h
new file mode 100644
index 0000000..efab088
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/VsockClientImpl.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class com_intel_clipboardagent_VsockClientImpl */
+
+#ifndef _Included_com_intel_clipboardagent_VsockClientImpl
+#define _Included_com_intel_clipboardagent_VsockClientImpl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_intel_clipboardagent_VsockClientImpl
+ * Method: socketCreate
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_socketCreate
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_intel_clipboardagent_VsockClientImpl
+ * Method: connect
+ * Signature: (Lcom/intel/clipboardagent/VsockAddress;)V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_connect
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: com_intel_clipboardagent_VsockClientImpl
+ * Method: close
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_close
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_intel_clipboardagent_VsockClientImpl
+ * Method: write
+ * Signature: ([BII)V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_write
+ (JNIEnv *, jobject, jbyteArray, jint, jint);
+
+/*
+ * Class: com_intel_clipboardagent_VsockClientImpl
+ * Method: read
+ * Signature: ([BII)I
+ */
+JNIEXPORT jint JNICALL Java_com_intel_clipboardagent_VsockClientImpl_read
+ (JNIEnv *, jobject, jbyteArray, jint, jint);
+
+/*
+ * Class: com_intel_clipboardagent_VsockClientImpl
+ * Method: writeInt
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_intel_clipboardagent_VsockClientImpl_writeInt
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: com_intel_clipboardagent_VsockClientImpl
+ * Method: readInt
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_intel_clipboardagent_VsockClientImpl_readInt
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/penguinpeak/ClipboardAgent/jni/adapter.cpp b/penguinpeak/ClipboardAgent/jni/adapter.cpp
new file mode 100644
index 0000000..963759f
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/adapter.cpp
@@ -0,0 +1,201 @@
+#include "adapter.h"
+
+JavaVM* gVm = nullptr;
+taf::gRPCServer* g_server_ = nullptr;
+std::map AdapterFactory::jadapter_map;
+
+static std::map< std::string, jclass > jclass_map;
+
+JNIEnv* getenv() {
+ JNIEnv *env = nullptr;
+ int getEnvStat = gVm->GetEnv((void **)&env, JNI_VERSION_1_6);
+ if (getEnvStat == JNI_EDETACHED) {
+ if (gVm->AttachCurrentThread(&env, NULL) != 0) {
+ LOG_ERROR("GetEnv: not attached. Failed to attach");
+ }
+ } else if (getEnvStat == JNI_OK) {
+ //
+ } else if (getEnvStat == JNI_EVERSION) {
+ LOG_ERROR("GetEnv: version not supported");
+ }
+ return env;
+}
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
+ JNIEnv *env;
+ std::string compName;
+ if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) {
+ LOG_ERROR("In OnLoad, failed to GetEnv");
+ return JNI_ERR;
+ }
+ jclass tmp = nullptr;
+ tmp = env->FindClass("com/intel/clipboardagent/ClipboardComponent");
+ if (tmp!= nullptr) {
+ jclass_map.insert({"ClipboardComponent", (jclass)env->NewGlobalRef(tmp)});
+ }
+ tmp = env->FindClass("com/intel/clipboardagent/AppstatusComponent");
+ if (tmp!= nullptr) {
+ compName = "AppstatusComponent";
+ jclass_map.insert({compName , (jclass)env->NewGlobalRef(tmp)});
+ AdapterFactory::AddAdapter(compName, new AppStatusAdapter(compName));
+ }
+ tmp = env->FindClass("com/intel/clipboardagent/NotificationComponent");
+ if (tmp!= nullptr) {
+ compName = "NotificationComponent";
+ jclass_map.insert({compName , (jclass)env->NewGlobalRef(tmp)});
+ AdapterFactory::AddAdapter(compName, new NotificationAdapter(compName));
+ }
+ // Setup gRPC Server
+ g_server_ = new taf::gRPCServer("vsock:-1:50051");
+ //g_server_ = new taf::gRPCServer("127.0.0.1:8787");
+ LOG_INFO("Created gRPC Server\n");
+ return JNI_VERSION_1_6;
+}
+
+void AdapterFactory::AddAdapter(std::string& name, ServiceAdapter* adapter) {
+ if (GetAdapter(name) == nullptr) {
+ jadapter_map.insert({name, adapter});
+ }
+}
+
+ServiceAdapter* AdapterFactory::GetAdapter(std::string& name) {
+ std::map< std::string, ServiceAdapter*>::iterator it;
+ it = jadapter_map.find(name);
+ return (it != jadapter_map.end()) ? it->second: nullptr;
+}
+
+void AdapterFactory::RemoveAll() {
+ for (auto adapter : jadapter_map) {
+ delete adapter.second;
+ }
+ jadapter_map.clear();
+}
+
+JavaComponent::~JavaComponent(){
+ JNIEnv* env = getenv();
+ jclass reqClass = GetJClass();
+ jobject singleInstance = GetSingletonInstance(reqClass);
+ jmethodID reqMethod = env->GetMethodID(reqClass, "stop", "()V");
+ env->CallVoidMethod(singleInstance, reqMethod);
+}
+
+void JavaComponent::init() {
+ JNIEnv* env = getenv();
+ jclass reqClass = GetJClass();
+ jobject singleInstance = GetSingletonInstance(reqClass);
+ jmethodID reqMethod = env->GetMethodID(reqClass, "init", "()V");
+ env->CallVoidMethod(singleInstance, reqMethod);
+}
+
+void JavaComponent::stop() {
+ JNIEnv* env = getenv();
+ jclass reqClass = GetJClass();
+ jobject singleInstance = GetSingletonInstance(reqClass);
+ jmethodID reqMethod = env->GetMethodID(reqClass, "stop", "()V");
+ env->CallVoidMethod(singleInstance, reqMethod);
+}
+
+void JavaComponent::ProcessMsg(std::string& msg, uint64_t hndl) {
+ LOG_INFO("Process msg - %s\n", msg.c_str());
+ JNIEnv *env = getenv();
+ jclass reqClass = GetJClass();
+ jobject singleInstance = GetSingletonInstance(reqClass);
+ jmethodID reqMethod = env->GetMethodID(reqClass, "processMsg", "(Ljava/lang/String;J)V");
+ jstring str = env->NewStringUTF(msg.c_str());
+ env->CallVoidMethod(singleInstance, reqMethod, str, static_cast(hndl));
+}
+
+jclass JavaComponent::GetJClass() {
+ std::map< std::string, jclass >::iterator it;
+ jclass reqClass = nullptr;
+ it = jclass_map.find(java_class_name.c_str());
+ if (it != jclass_map.end()) {
+ reqClass = it->second;
+ }
+ return reqClass;
+}
+
+jobject JavaComponent::GetSingletonInstance(jclass reqClass) {
+ JNIEnv *env = getenv();
+ std::string sig = "()Lcom/intel/clipboardagent/"+java_class_name+";";
+ jmethodID instMethod = env->GetStaticMethodID(reqClass, "getInstance", sig.c_str());
+ jobject singleInstance = env->CallStaticObjectMethod(reqClass, instMethod);
+ return singleInstance;
+}
+
+void JavaObjectHelper::init() {
+ JNIEnv *env = getenv();
+ class_ = env->GetObjectClass(obj_);
+}
+
+int JavaObjectHelper::GetIntField(const char* fldNm) {
+ JNIEnv *env = getenv();
+ jfieldID fld = env->GetFieldID(class_, fldNm, "I");
+ return env->GetIntField(obj_, fld);
+}
+
+const char* JavaObjectHelper::GetStringField(const char* fldNm) {
+ JNIEnv *env = getenv();
+ jfieldID fld = env->GetFieldID(class_, fldNm, "Ljava/lang/String;");
+ jstring str = (jstring) env->GetObjectField(obj_, fld);
+ return env->GetStringUTFChars(str, 0);
+}
+
+void AppStatusAdapter::SendResponse(JavaObjectHelper* jobjHelper) {
+ AppStatusResponse resp;
+ resp.set_app_name(jobjHelper->GetStringField("app_name"));
+ if (svc_ != nullptr && !svc_->Observe_Response(&resp)) {
+ stop();
+ auto stream = svc_->GET_API_STREAM(Observe);
+ if (stream != nullptr) {
+ // Something wrong with the stream, end the call
+ stream->WritesDone();
+ stream->Finish();
+ }
+ }
+}
+
+taf::Service* AppStatusAdapter::GetService() {
+ if (svc_ == nullptr) {
+ svc_ = new AppStatusAdapter::Service(this);
+ }
+ return svc_;
+}
+
+bool AppStatusAdapter::Service::Observe(const AppStatusRequest* /*msg*/) {
+ LOG_INFO("Initializing AppStatus");
+ adapter_->init();
+ return true;
+}
+
+void NotificationAdapter::SendResponse(JavaObjectHelper* jobjHelper) {
+ NotificationResponse resp;
+ resp.set_package(jobjHelper->GetStringField("packageName"));
+ resp.set_key(jobjHelper->GetStringField("key"));
+ resp.set_group_key(jobjHelper->GetStringField("groupKey"));
+ resp.set_message(jobjHelper->GetStringField("message"));
+ resp.set_priority(jobjHelper->GetIntField("priority"));
+ if (svc_ != nullptr && !svc_->Observe_Response(&resp)) {
+ stop();
+ auto stream = svc_->GET_API_STREAM(Observe);
+ if (stream != nullptr) {
+ // Something wrong with the stream, end the call
+ stream->WritesDone();
+ stream->Finish();
+ }
+ }
+}
+
+taf::Service* NotificationAdapter::GetService() {
+ if (svc_ == nullptr) {
+ svc_ = new NotificationAdapter::Service(this);
+ }
+ return svc_;
+}
+
+bool NotificationAdapter::Service::Observe(const NotificationRequest* /*msg*/) {
+ LOG_INFO("Initializing Notification sync");
+ adapter_->init();
+ return true;
+}
+
diff --git a/penguinpeak/ClipboardAgent/jni/adapter.h b/penguinpeak/ClipboardAgent/jni/adapter.h
new file mode 100644
index 0000000..985e690
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/adapter.h
@@ -0,0 +1,117 @@
+#include
+#include "proto/appstatus.h"
+#include "proto/notification.h"
+#include "grpc/server.h"
+
+extern JavaVM* gVm;
+extern taf::gRPCServer* g_server_;
+
+using namespace com::android::guest;
+
+class JavaComponent {
+public:
+ JavaComponent(std::string name) { java_class_name = name; }
+ ~JavaComponent();
+ void init();
+ void stop();
+ void ProcessMsg(std::string& msg, uint64_t hndl);
+private:
+ jclass GetJClass();
+ jobject GetSingletonInstance(jclass reqClass);
+
+ std::string java_class_name;
+};
+
+class JavaObjectHelper {
+public:
+ JavaObjectHelper(jobject obj) { obj_ = obj; init(); }
+ int GetIntField(const char* fldNm);
+ const char* GetStringField(const char* fldNm);
+private:
+ void init();
+
+ jobject obj_;
+ jclass class_;
+};
+
+class ServiceAdapter {
+public:
+ ServiceAdapter(std::string& name) { comp_ = new JavaComponent(name); }
+ virtual ~ServiceAdapter() {
+ delete comp_;
+ comp_ = nullptr;
+ }
+ virtual void SendResponse(JavaObjectHelper* payload) = 0;
+ inline void Register() {
+ g_server_->RegisterService(GetService());
+ }
+ inline void init() { comp_->init(); }
+ inline void stop() { comp_->stop(); }
+
+protected:
+ inline void ProcessRequest(std::string& payload) {
+ comp_->ProcessMsg(payload, 0);
+ }
+ virtual taf::Service* GetService() = 0;
+ JavaComponent* comp_;
+};
+
+class AppStatusAdapter : public ServiceAdapter {
+public:
+ AppStatusAdapter(std::string& name) : ServiceAdapter(name), svc_(nullptr) { }
+ virtual ~AppStatusAdapter() {
+ if (svc_ != nullptr) {
+ delete svc_;
+ svc_ = nullptr;
+ }
+ }
+ void SendResponse(JavaObjectHelper* payload) override;
+
+ class Service : public AppStatusImpl::Service {
+ public:
+ Service(ServiceAdapter* adapter) { adapter_ = adapter; }
+ bool Observe(const AppStatusRequest*) override;
+
+ ServiceAdapter* adapter_;
+ };
+
+protected:
+ taf::Service* GetService() override;
+private:
+ Service* svc_;
+};
+
+class NotificationAdapter : public ServiceAdapter {
+public:
+ NotificationAdapter(std::string& name) : ServiceAdapter(name), svc_(nullptr) { }
+ virtual ~NotificationAdapter() {
+ if (svc_ != nullptr) {
+ delete svc_;
+ svc_ = nullptr;
+ }
+ }
+ void SendResponse(JavaObjectHelper* payload) override;
+
+ class Service : public NotificationImpl::Service {
+ public:
+ Service(ServiceAdapter* adapter) { adapter_ = adapter; }
+ bool Observe(const NotificationRequest* /*msg*/) override;
+
+ ServiceAdapter* adapter_;
+ };
+
+protected:
+ taf::Service* GetService() override;
+private:
+ Service* svc_;
+};
+
+class AdapterFactory {
+public:
+ static void AddAdapter(std::string& name, ServiceAdapter* adapter);
+ static ServiceAdapter* GetAdapter(std::string& name);
+ static void RemoveAll();
+private:
+ static std::map jadapter_map;
+};
+
diff --git a/penguinpeak/ClipboardAgent/jni/appstatus.cpp b/penguinpeak/ClipboardAgent/jni/appstatus.cpp
new file mode 100644
index 0000000..b0ffef5
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/appstatus.cpp
@@ -0,0 +1,19 @@
+#include
+#include
+#include "grpc/client.h"
+
+#include "proto/appstatus.h"
+
+using namespace ::com::android::guest;
+
+bool AppStatusImpl::Stub::Observe_Response(const AppStatusResponse* msg) {
+ if (msg != nullptr) {
+ std::cout << "Received AppStatus message:" << msg->app_name() << std::endl;
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "/opt/cfc/mwc/bin/msg_agent localhost 3000 CRASHAPP %s", msg->app_name().c_str());
+ std::cout << "Running cmd: " << cmd << std::endl;
+ system(cmd);
+ }
+ return true;
+}
+
diff --git a/penguinpeak/ClipboardAgent/jni/notification.cpp b/penguinpeak/ClipboardAgent/jni/notification.cpp
new file mode 100644
index 0000000..8c0c846
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/notification.cpp
@@ -0,0 +1,45 @@
+#include
+#include
+#include "grpc/client.h"
+
+#include "proto/appstatus.h"
+#include "proto/notification.h"
+
+using namespace ::com::android::guest;
+
+bool NotificationImpl::Stub::Observe_Response(const NotificationResponse* msg) {
+ if (msg != nullptr) {
+ std::cout << "Received Notification message:" << msg->message() << std::endl;
+ char cmd[512];
+ //snprintf(cmd, sizeof(cmd), "notify-send -a %s '%s'", msg->package().c_str(), msg->message().c_str());
+ snprintf(cmd, sizeof(cmd), "python3 /opt/cfc/host_agent/bin/notify.py -P %s -k '%s' -g '%s' -m '%s' -p %d", msg->package().c_str(), msg->key().c_str(), msg->group_key().c_str(), msg->message().c_str(), msg->priority());
+ std::cout << "Running cmd: " << cmd << std::endl;
+ system(cmd);
+ }
+ return true;
+}
+
+int main() {
+ auto client = taf::Client::Create("vsock:3:50051", taf::DispatchKind::kgRPC);
+ AppStatusImpl::Stub appStatusStub;
+ NotificationImpl::Stub notificationStub;
+ std::cout << "Registering Stub" << std::endl;
+ client->Bind(&appStatusStub);
+ client->Bind(¬ificationStub);
+ AppStatusRequest req;
+ NotificationRequest notificationReq;
+ std::cout << "Initiate AppStatus stream" << std::endl;
+ appStatusStub.Observe(&req);
+ std::cout << "Initiate Notification stream" << std::endl;
+ notificationStub.Observe(¬ificationReq);
+ // Wait for both API streams to end
+ auto appStatusStream = appStatusStub.GET_API_STREAM(Observe);
+ if(appStatusStream != nullptr) {
+ appStatusStream->WaitForFinish();
+ }
+ auto notificationStream = notificationStub.GET_API_STREAM(Observe);
+ if (notificationStream != nullptr) {
+ notificationStream->WaitForFinish();
+ }
+ std::cout << "Stream ended" << std::endl;
+}
diff --git a/penguinpeak/ClipboardAgent/jni/proto/appstatus-protogen.inp b/penguinpeak/ClipboardAgent/jni/proto/appstatus-protogen.inp
new file mode 100644
index 0000000..69da964
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/proto/appstatus-protogen.inp
@@ -0,0 +1,11 @@
+[Template]
+Path=./../../../../../taf-grpc/core/templates/observer.template
+
+[TemplateParams]
+Class_ServiceName=AppStatus
+Type_ObserveReq=AppStatusRequest
+Type_ObserveResp=AppStatusResponse
+
+[Proto]
+MessagePath=proto/appstatus.proto
+PackageName=com.android.guest
diff --git a/penguinpeak/ClipboardAgent/jni/proto/appstatus.proto b/penguinpeak/ClipboardAgent/jni/proto/appstatus.proto
new file mode 100644
index 0000000..240eaa0
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/proto/appstatus.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+
+package com.android.guest;
+
+message AppStatusRequest {
+ int32 req_num = 1;
+}
+
+message AppStatusResponse {
+ string app_name = 1;
+}
+
diff --git a/penguinpeak/ClipboardAgent/jni/proto/notification-protogen.inp b/penguinpeak/ClipboardAgent/jni/proto/notification-protogen.inp
new file mode 100644
index 0000000..75df9ea
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/proto/notification-protogen.inp
@@ -0,0 +1,11 @@
+[Template]
+Path=./../../../../../taf-grpc/core/templates/observer.template
+
+[TemplateParams]
+Class_ServiceName=Notification
+Type_ObserveReq=NotificationRequest
+Type_ObserveResp=NotificationResponse
+
+[Proto]
+MessagePath=proto/notification.proto
+PackageName=com.android.guest
diff --git a/penguinpeak/ClipboardAgent/jni/proto/notification.proto b/penguinpeak/ClipboardAgent/jni/proto/notification.proto
new file mode 100644
index 0000000..dc08963
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/jni/proto/notification.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package com.android.guest;
+
+message NotificationRequest {
+ int32 req_num = 1;
+}
+
+message NotificationResponse {
+ string package = 1;
+ string key = 2;
+ string group_key = 3;
+ string message = 4;
+ int32 priority = 5;
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/AppStatusData.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/AppStatusData.java
new file mode 100644
index 0000000..7907f09
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/AppStatusData.java
@@ -0,0 +1,5 @@
+package com.intel.clipboardagent;
+
+public class AppStatusData {
+ String app_name;
+}
\ No newline at end of file
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/AppstatusComponent.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/AppstatusComponent.java
new file mode 100644
index 0000000..cad6866
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/AppstatusComponent.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import android.app.Service;
+import android.content.Intent;
+import android.util.Log;
+import java.util.HashMap;
+import java.util.List;
+import com.intel.clipboardagent.DispatchHelper;
+import android.content.Context;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.content.pm.PackageManager;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
+
+public class AppstatusComponent {
+ private static final String TAG = "AppstatusComponent";
+ private static AppstatusComponent single_instance = null;
+ private DispatchHelper dH;
+ private ActivityManager mActivityManager;
+ private HashMap uidPrevImpMap = new HashMap();
+ private static final int FOREGROUND_IMPORTANCE_CUTOFF = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+
+ private AppstatusComponent(){
+ }
+
+ public static AppstatusComponent getInstance() {
+ if (single_instance == null) {
+ single_instance = new AppstatusComponent();
+ }
+ return single_instance;
+ }
+
+ public void init() {
+ dH = DispatchHelper.getInstance();
+ Log.d(TAG, "addOnUidImportanceListener");
+ mActivityManager = (ActivityManager) dH.mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener, FOREGROUND_IMPORTANCE_CUTOFF);
+
+ }
+
+ public void stop() {
+ if (mActivityManager != null) {
+ Log.d(TAG, "removeOnUidImportanceListener");
+ mActivityManager.removeOnUidImportanceListener(mOnUidImportanceListener);
+ }
+ }
+
+ private String getPackageName(int uid) {
+ String packageName = "";
+ String[] packages = dH.mContext.getPackageManager().getPackagesForUid(uid);
+ if (packages == null) {
+ Log.d(TAG, "No package is associated with that uid, do nothing");
+ } else if (packages.length == 1) {
+ packageName = packages[0];
+ } else {
+ Log.d(TAG, "Multiple packages associated with the uid, should see what to do");
+ }
+ return packageName;
+ }
+
+ private boolean isHomeForeground(){
+ try {
+ int homeId = dH.mContext.getPackageManager().getPackageUid("com.android.launcher3", 0);
+ if (mActivityManager.getUidImportance(homeId) == IMPORTANCE_FOREGROUND)
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ private boolean killLG(String appName) {
+ List recentTasks = mActivityManager.getRecentTasks(10, 0);
+ boolean kill = true;
+ for (ActivityManager.RecentTaskInfo taskInfo : recentTasks) {
+ //Log.d(TAG, "In AHSFunc, taskinfo.isRunning " + taskInfo.isRunning);
+ //Log.d(TAG, "In AHSFunc, taskinfo.isVisible " + taskInfo.isVisible());
+ if ((taskInfo.baseActivity != null) && taskInfo.isRunning && taskInfo.isVisible() && appName.equals(taskInfo.baseActivity.getPackageName())) {
+ kill = false;
+ break;
+ }
+ }
+ return kill;
+ }
+
+ private void dumpTaskInfo() {
+ List recentTasks = mActivityManager.getRecentTasks(10, 0);
+ for (ActivityManager.RecentTaskInfo taskInfo : recentTasks) {
+ Log.d(TAG, "taskInfo = " + taskInfo.toString());
+ }
+ }
+
+ private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
+ new ActivityManager.OnUidImportanceListener() {
+ @Override
+ public void onUidImportance(final int uid, final int importance){
+ Log.d(TAG, "In onUidImportance event, uid = " + uid + " and importance = " + importance);
+ String appName = getPackageName(uid);
+ if (appName.isEmpty()) {
+ Log.d(TAG, "No app associated with uid, so return");
+ return;
+ }
+ Log.d(TAG, "In onUidImportance Listener, processing App = " + appName);
+ // dumpTaskInfo();
+ if (uidPrevImpMap.containsKey(uid)) {
+ int prevImp = uidPrevImpMap.get(uid);
+ Log.d(TAG, "prev imp value of uid " + uid + " is " + prevImp);
+ if (prevImp == IMPORTANCE_FOREGROUND) {
+ if (importance == IMPORTANCE_GONE) {
+ Log.d(TAG, "App with uid " + uid + " killed, send message to host");
+ Log.d(TAG, "1:: Sending message to host");
+ AppStatusData appstatusData = new AppStatusData();
+ appstatusData.app_name = appName;
+ dH.sendMsg("AppstatusComponent", appstatusData, 0);
+ } else if(importance >= IMPORTANCE_VISIBLE) { // && importance <= IMPORTANCE_CACHED) {
+ Log.d(TAG, "App with uid " + uid + " moved from foreground to background");
+ if (killLG(appName)) {
+ AppStatusData appstatusData = new AppStatusData();
+ appstatusData.app_name = appName;
+ Log.d(TAG, "2:: Sending message to host");
+ dH.sendMsg("AppstatusComponent", appstatusData, 0);
+ }
+ }
+ }
+ if (importance == IMPORTANCE_GONE) {
+ Log.d(TAG, "App with uid " + uid + " killed, remove from the map");
+ uidPrevImpMap.remove(uid);
+ } else {
+ uidPrevImpMap.put(uid, importance);
+ }
+ } else {
+ uidPrevImpMap.put(uid, importance);
+ }
+ }
+ };
+
+ /*public void processMsg(String content, long handle) {
+ try {
+ int uid = dH.mContext.getPackageManager().getPackageUid(content, 0);
+ // can diff uid have same handle?
+ uidAppnameMap.put(uid, content);
+ uidChannelMap.put(uid, handle);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ }*/
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardAgent.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardAgent.java
new file mode 100644
index 0000000..638f8bd
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardAgent.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import android.app.Application;
+import android.content.Intent;
+import android.util.Log;
+
+public class ClipboardAgent extends Application {
+ private static final String TAG = "ClipboardAgent";
+ private static final String SERVICE_NAME = "ClipboardAgent";
+
+
+ public void onCreate() {
+ Log.d(TAG, "Application onCreate");
+ super.onCreate();
+
+ startService(new Intent(this, ClipboardService.class));
+ startService(new Intent(this, GuestVsockCommService.class));
+ startService(new Intent(this, NotificationListener.class));
+ }
+
+ public void onTerminate() {
+ super.onTerminate();
+ }
+
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardComponent.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardComponent.java
new file mode 100644
index 0000000..16a3e90
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardComponent.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import android.app.Service;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Intent;
+import android.util.Log;
+import com.intel.clipboardagent.DispatchHelper;
+import android.content.Context;
+import static android.content.Context.CLIPBOARD_SERVICE;
+
+public class ClipboardComponent {
+ private static final String TAG = "ClipboardComponent";
+ private static final String CLIPBOARD_SERVICE_LABEL = "IntelClipboardService";
+ private static ClipboardComponent single_instance = null;
+ private ClipboardManager mClipboardManager;
+ private DispatchHelper dH;
+ private long mChannelHandle = 0;
+
+ private ClipboardComponent(){
+ }
+
+ public static ClipboardComponent getInstance() {
+ if (single_instance == null) {
+ single_instance = new ClipboardComponent();
+ }
+ return single_instance;
+ }
+
+ public void init() {
+ dH = DispatchHelper.getInstance();
+ Log.d(TAG, "addPrimaryClipChangedListener");
+ mClipboardManager =
+ (ClipboardManager) dH.mContext.getSystemService(CLIPBOARD_SERVICE);
+ mClipboardManager.addPrimaryClipChangedListener(
+ mOnPrimaryClipChangedListener);
+ }
+
+ public void stop() {
+ if (mClipboardManager != null) {
+ Log.d(TAG, "removePrimaryClipChangedListener");
+ mClipboardManager.removePrimaryClipChangedListener(
+ mOnPrimaryClipChangedListener);
+ }
+ }
+
+
+ private final ClipboardManager.OnPrimaryClipChangedListener mOnPrimaryClipChangedListener =
+ new ClipboardManager.OnPrimaryClipChangedListener() {
+ @Override
+ public void onPrimaryClipChanged() {
+ ClipData mclipData = mClipboardManager.getPrimaryClip();
+ // This clip originated from the same service, suppress it.
+ if (CLIPBOARD_SERVICE_LABEL.equals(mclipData.getDescription().getLabel())) {
+ return;
+ }
+ CharSequence mText = mclipData.getItemAt(0).getText();
+ dH.sendMsg("ClipboardComponent", mText.toString(), mChannelHandle);
+ }
+ };
+
+ public void processMsg(String content, long handle) {
+ ClipData mclipData = mClipboardManager.getPrimaryClip();
+ mclipData = ClipData.newPlainText(CLIPBOARD_SERVICE_LABEL, content);
+ mClipboardManager.setPrimaryClip(mclipData);
+ mChannelHandle = handle;
+ }
+
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardService.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardService.java
new file mode 100644
index 0000000..55c9064
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/ClipboardService.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import android.app.Service;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import com.intel.clipboardagent.VsockClientImpl;
+import com.intel.clipboardagent.VsockAddress;
+
+public class ClipboardService extends Service{
+ private static final String TAG = "ClipboardAgent";
+ private static final String CLIPBOARD_SERVICE_LABEL = "IntelClipboardService";
+ private static final int DEFAULT_DATA_LENGTH = 4096;
+ private static final int MAX_DATA_LENGTH = 512*1024;
+ private ExecutorService mThreadPool = Executors.newSingleThreadExecutor();
+ private ClipboardManager mClipboardManager;
+ private Vsock mVsock;
+ private VsockAddress mVsockAddress;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.d(TAG, "In ClipboardService onCreate");
+
+ mClipboardManager =
+ (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
+ mClipboardManager.addPrimaryClipChangedListener(
+ mOnPrimaryClipChangedListener);
+ // TODO: remove hard code on vsock port
+ mVsockAddress = new VsockAddress(VsockAddress.VMADDR_CID_HOST, 77777);
+ mVsock = new Vsock(mVsockAddress);
+
+ mThreadPool.execute(new HandleHostVsockContent());
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ if (mClipboardManager != null) {
+ Log.d(TAG, "removePrimaryClipChangedListener");
+ mClipboardManager.removePrimaryClipChangedListener(
+ mOnPrimaryClipChangedListener);
+ }
+ try {
+ mVsock.close();
+ } catch (IOException exception) {
+ Log.e(TAG, "Error on closing Vsock: " + exception.getMessage());
+ }
+
+ }
+
+ private final ClipboardManager.OnPrimaryClipChangedListener mOnPrimaryClipChangedListener =
+ new ClipboardManager.OnPrimaryClipChangedListener() {
+ @Override
+ public void onPrimaryClipChanged() {
+ ClipData mclipData = mClipboardManager.getPrimaryClip();
+ // This clip originated from the same service, suppress it.
+ if (CLIPBOARD_SERVICE_LABEL.equals(mclipData.getDescription().getLabel())) {
+ return;
+ }
+ CharSequence mText = mclipData.getItemAt(0).getText();
+ byte[] mBytes = mText.toString().getBytes(StandardCharsets.UTF_8);
+
+ try{
+ mVsock.getOutputStream().writeInt(mBytes.length);
+ int writeLength = (mBytes.length < MAX_DATA_LENGTH) ? mBytes.length : MAX_DATA_LENGTH;
+ // If Clipboard is cleared, nothing to send
+ if (writeLength > 0) {
+ mVsock.getOutputStream().write(mBytes, 0, writeLength);
+ }
+ } catch (IOException exception) {
+ Log.e(TAG, "Error on handling clipboard data: " + exception.getMessage());
+ }
+ }
+ };
+
+ // Class HandleHostVsockContent should receive vsock data from remote host
+ private class HandleHostVsockContent implements Runnable {
+ private static final String TAG = "ClipboardAgent";
+
+ private HandleHostVsockContent() {
+ }
+
+ @Override
+ public void run() {
+ // TODO: Data length is hard code here for 4096.
+ byte[] buffer = new byte[DEFAULT_DATA_LENGTH];
+ try {
+ mVsock.connect();
+ } catch (IOException exception) {
+ Log.e(TAG, "Failed to connect: " + exception.getMessage());
+ }
+ while (true) {
+ boolean bReconnect = false;
+ byte[] bytes = buffer;
+ String content = "";
+ try {
+ int length = mVsock.getInputStream().readInt();
+ if (length < 0 || length > MAX_DATA_LENGTH) {
+ Log.wtf(TAG, "Unexpected data size :"+length, new Exception("Unexpected data size"));
+ continue;
+ }
+
+ if (length > DEFAULT_DATA_LENGTH) {
+ bytes = new byte[length];
+ }
+
+ if (length > 0) {
+ mVsock.getInputStream().read(bytes, 0, length);
+ content = new String(bytes, 0, length, StandardCharsets.UTF_8);
+ }
+ ClipData mclipData = mClipboardManager.getPrimaryClip();
+ mclipData = ClipData.newPlainText(CLIPBOARD_SERVICE_LABEL, content);
+ mClipboardManager.setPrimaryClip(mclipData);
+
+ } catch (IOException exception) {
+ if (exception.toString().contains("Connection reset") ||
+ exception.toString().contains("Connection is closed by peer")) {
+ Log.e(TAG, "Connection reset, attempting to reconnect");
+ bReconnect = true;
+ } else {
+ Log.e(TAG, "Error on handling host Vsock: " + exception.getMessage());
+ }
+ }
+ if (bReconnect) {
+ try {
+ mVsock.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close vsock: " + e.getMessage());
+ }
+ try {
+ mVsock = new Vsock(mVsockAddress);
+ mVsock.connect();
+ Thread.sleep(1000);
+ } catch (IOException e) {
+ Log.e(TAG, "Error reconnecting... " + e.getMessage());
+ } catch (InterruptedException x) {}
+ }
+ }
+ }
+ }
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/DispatchHelper.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/DispatchHelper.java
new file mode 100644
index 0000000..e4026dc
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/DispatchHelper.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+import android.content.Context;
+
+public class DispatchHelper {
+ static {
+ System.loadLibrary("VsockMsgDispatch");
+ }
+ private static final String TAG = "DispatchHelper";
+ private static DispatchHelper single_instance = null;
+ public Context mContext;
+ private DispatchHelper() {
+ }
+ public static DispatchHelper getInstance() {
+ if (single_instance == null) {
+ single_instance = new DispatchHelper();
+ }
+ return single_instance;
+ }
+
+ public native void registerComponent(String className);
+ public native void sendMsg(String className, Object msg, long handle);
+ public native void start();
+ public native void stop();
+
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/GuestVsockCommService.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/GuestVsockCommService.java
new file mode 100644
index 0000000..8094f52
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/GuestVsockCommService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+import com.intel.clipboardagent.DispatchHelper;
+import android.content.Context;
+
+public class GuestVsockCommService extends Service{
+ private DispatchHelper dH;
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ dH = DispatchHelper.getInstance();
+ dH.mContext = this.getApplicationContext();
+ dH.registerComponent("ClipboardComponent");
+ dH.registerComponent("AppstatusComponent");
+ dH.registerComponent("NotificationComponent");
+ dH.start();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ dH.stop();
+ }
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/MainActivity.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/MainActivity.java
new file mode 100644
index 0000000..158be8d
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/MainActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ finish();
+ }
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationComponent.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationComponent.java
new file mode 100644
index 0000000..51ae999
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationComponent.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import android.app.Service;
+import android.content.Intent;
+import android.util.Log;
+import com.intel.clipboardagent.DispatchHelper;
+import android.content.Context;
+import android.app.ActivityManager;
+import android.content.pm.PackageManager;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.content.ComponentName;
+import android.app.NotificationManager;
+import java.util.List;
+
+public class NotificationComponent {
+ private static final String TAG = "NotificationComponent";
+ private static NotificationComponent single_instance = null;
+ private DispatchHelper dH;
+ private NotificationListener mListener;
+
+ private NotificationComponent(){
+ }
+
+ public static NotificationComponent getInstance() {
+ if (single_instance == null) {
+ single_instance = new NotificationComponent();
+ }
+ return single_instance;
+ }
+
+ public void init() {
+ dH = DispatchHelper.getInstance();
+ Log.d(TAG, "In init");
+ mListener = new NotificationListener();
+ mListener.setNotificationsChangedListener(mNotificationsChangedListener);
+ ComponentName cn = ComponentName.unflattenFromString("com.intel.clipboardagent/com.intel.clipboardagent.NotificationListener");
+ NotificationManager nm = dH.mContext.getSystemService(NotificationManager.class);
+ if (nm.isNotificationListenerAccessGranted(cn)) {
+ Log.d(TAG, "Has notification acess");
+ }
+ }
+
+ public void stop() {
+ Log.d(TAG, "In stop");
+ if (mListener != null) {
+ mListener.removeNotificationsChangedListener();
+ }
+ }
+
+ private final NotificationListener.NotificationsChangedListener mNotificationsChangedListener = new NotificationListener.NotificationsChangedListener() {
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn) {
+ Log.d(TAG, "In NotificationComponent onNotificationPosted");
+ Log.d(TAG, "ID :" + sbn.getId() + "\t" + sbn.getNotification().tickerText +"\t" + sbn.getPackageName());
+ Log.d(TAG, "ID :" + sbn.isGroup() + "\t" + sbn.getKey() +"\t" + sbn.toString() +"\t" + sbn.getNotification().priority);
+ NotificationData notificationdata = new NotificationData();
+ notificationdata.packageName = sbn.getPackageName();
+ notificationdata.key = sbn.getKey();
+ notificationdata.groupKey = sbn.getGroupKey();
+ if (sbn.getNotification().tickerText != null) {
+ notificationdata.message = sbn.getNotification().tickerText.toString();
+ }
+ notificationdata.priority = sbn.getNotification().priority;
+ dH.sendMsg("NotificationComponent", notificationdata, 0);
+ }
+ };
+
+}
+
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationData.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationData.java
new file mode 100644
index 0000000..cfe09f6
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationData.java
@@ -0,0 +1,9 @@
+package com.intel.clipboardagent;
+
+public class NotificationData {
+ String packageName;
+ String key;
+ String groupKey;
+ String message;
+ int priority;
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationListener.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationListener.java
new file mode 100644
index 0000000..bc519e2
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/NotificationListener.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import android.app.Service;
+import android.content.Intent;
+import android.util.Log;
+import com.intel.clipboardagent.DispatchHelper;
+import android.content.Context;
+import android.app.ActivityManager;
+import android.content.pm.PackageManager;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.content.ComponentName;
+
+public class NotificationListener extends NotificationListenerService {
+ private static final String TAG = "NotificationListener";
+ private static NotificationsChangedListener sNotificationsChangedListener;
+
+ public interface NotificationsChangedListener {
+ void onNotificationPosted(StatusBarNotification sbn);
+ }
+
+ public NotificationListener() {
+ sNotificationsChangedListener = null;
+ }
+
+ public static void setNotificationsChangedListener(NotificationsChangedListener listener) {
+ sNotificationsChangedListener = listener;
+ }
+
+ public static void removeNotificationsChangedListener() {
+ sNotificationsChangedListener = null;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn) {
+ Log.d(TAG, "In onNotificationPosted");
+ if (sNotificationsChangedListener != null) {
+ sNotificationsChangedListener.onNotificationPosted(sbn);
+ }
+ }
+}
+
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/Vsock.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/Vsock.java
new file mode 100644
index 0000000..1a7455d
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/Vsock.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketException;
+
+public final class Vsock extends VsockBaseVSock implements Closeable {
+ private boolean connected = false;
+ private VsockOutputStream outputStream;
+ private VsockInputStream inputStream;
+ private VsockAddress mAddress;
+
+ public Vsock() {
+ }
+
+ public Vsock(VsockAddress address) {
+ mAddress = address;
+ }
+
+ public void connect() throws SocketException {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
+ if (connected) {
+ throw new SocketException("Socket already connected");
+ }
+ getImplementation().connect(mAddress);
+ connected = true;
+ }
+
+ public synchronized VsockOutputStream getOutputStream() throws IOException {
+ if (isClosed()) {
+ throw new SocketException("VSock is closed");
+ }
+ if (outputStream == null) {
+ outputStream = new VsockOutputStream(getImplementation());
+ }
+ return outputStream;
+ }
+
+ public synchronized VsockInputStream getInputStream() throws IOException {
+ if (isClosed()) {
+ throw new SocketException("VSock is closed");
+ }
+ if (inputStream == null) {
+ inputStream = new VsockInputStream(getImplementation());
+ }
+ return inputStream;
+ }
+
+ void postAccept() {
+ created = true;
+ connected = true;
+ }
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockAddress.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockAddress.java
new file mode 100644
index 0000000..99e831a
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockAddress.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import java.net.SocketAddress;
+import java.util.Objects;
+
+public final class VsockAddress extends SocketAddress {
+ public static final int VMADDR_CID_ANY = -1;
+ public static final int VMADDR_CID_HYPERVISOR = 0;
+ public static final int VMADDR_CID_RESERVED = 1;
+ public static final int VMADDR_CID_HOST = 2;
+ public static final int VMADDR_CID_PARENT = 3;
+
+ public static final int VMADDR_PORT_ANY = -1;
+ final int cid;
+ final int port;
+
+ public VsockAddress(int cid, int port) {
+ this.cid = cid;
+ this.port = port;
+ }
+
+ public int getCid() {
+ return cid;
+ }
+
+ public int getPort() {
+ return port;
+ }
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockBaseVSock.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockBaseVSock.java
new file mode 100644
index 0000000..bde6fc9
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockBaseVSock.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.SocketException;
+
+abstract class VsockBaseVSock implements Closeable {
+ protected final Object closeLock = new Object();
+ protected boolean closed = false;
+ protected boolean created = false;
+
+ private VsockClientImpl implementation;
+
+ private void createImplementation() throws SocketException {
+ implementation = new VsockClientImpl();
+ implementation.create();
+ created = true;
+ }
+
+ protected VsockClientImpl getImplementation() throws SocketException {
+ if (!created) {
+ createImplementation();
+ }
+ return implementation;
+ }
+
+ protected VsockClientImpl setImplementation() throws SocketException {
+ if(implementation == null) {
+ implementation = new VsockClientImpl();
+ }
+ return implementation;
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ synchronized (closeLock) {
+ if (isClosed())
+ return;
+ if (created)
+ getImplementation().close();
+ closed = true;
+ }
+ }
+
+ protected boolean isClosed() {
+ return closed;
+ }
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockClientImpl.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockClientImpl.java
new file mode 100644
index 0000000..57caf8c
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockClientImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import java.net.*;
+import java.io.*;
+
+public class VsockClientImpl {
+ static {
+ System.loadLibrary("VsocketClientImpl");
+ }
+
+ int fd = -1;
+
+ void create() throws SocketException {
+ socketCreate();
+ }
+
+ native void socketCreate() throws SocketException;
+ native void connect(VsockAddress address) throws SocketException;
+ native void close() throws IOException;
+ native void write(byte[] b, int off, int len) throws IOException;
+ native int read(byte[] b, int off, int len) throws IOException;
+
+ native void writeInt(int value) throws IOException;
+ native int readInt() throws IOException;
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockInputStream.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockInputStream.java
new file mode 100644
index 0000000..0ab8fcf
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockInputStream.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public final class VsockInputStream extends InputStream {
+ private final VsockClientImpl vSock;
+ private byte[] temp;
+
+ public VsockInputStream (VsockClientImpl vSock) {
+ this.vSock = vSock;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return vSock.read(b, off, len);
+ }
+
+ @Override
+ public int read() throws IOException {
+ temp = new byte[1];
+ int n = read(temp, 0, 1);
+ if (n <= 0) {
+ return -1;
+ }
+ return temp[0];
+ }
+
+ public int readInt() throws IOException {
+ return vSock.readInt();
+ }
+
+ @Override
+ public void close() throws IOException {
+ vSock.close();
+ super.close();
+ }
+}
diff --git a/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockOutputStream.java b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockOutputStream.java
new file mode 100644
index 0000000..6e2bdb6
--- /dev/null
+++ b/penguinpeak/ClipboardAgent/src/com/intel/clipboardagent/VsockOutputStream.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.clipboardagent;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public final class VsockOutputStream extends OutputStream {
+ private final VsockClientImpl vSock;
+ private final byte[] temp = new byte[1];
+
+ VsockOutputStream(VsockClientImpl vSock) {
+ this.vSock = vSock;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ temp[0] = (byte) b;
+ this.write(temp, 0, 1);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ vSock.write(b, off, len);
+ }
+
+ public void writeInt(int value) throws IOException {
+ vSock.writeInt(value);
+ }
+
+ @Override
+ public void close() throws IOException {
+ vSock.close();
+ super.close();
+ }
+}