ares test sandbox/aegis-test
authorminhoon.yi <minhoon.yi@samsung.com>
Thu, 24 Aug 2017 11:12:41 +0000 (20:12 +0900)
committerminhoon.yi <minhoon.yi@samsung.com>
Thu, 24 Aug 2017 11:12:41 +0000 (20:12 +0900)
Change-Id: Id491935698baec752ab36136c5466e45f813dbba

112 files changed:
AUTHORS
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
inc/amd.h [new file with mode: 0644]
inc/amd_api.h [new file with mode: 0644]
inc/amd_api_app_com.h [new file with mode: 0644]
inc/amd_api_app_status.h [new file with mode: 0644]
inc/amd_api_appinfo.h [new file with mode: 0644]
inc/amd_api_cynara.h [new file with mode: 0644]
inc/amd_api_inotify.h [new file with mode: 0644]
inc/amd_api_launch.h [new file with mode: 0644]
inc/amd_api_launch_context.h [new file with mode: 0644]
inc/amd_api_launchpad.h [new file with mode: 0644]
inc/amd_api_login_monitor.h [new file with mode: 0644]
inc/amd_api_noti.h [new file with mode: 0644]
inc/amd_api_request.h [new file with mode: 0644]
inc/amd_api_signal.h [new file with mode: 0644]
inc/amd_api_suspend.h [new file with mode: 0644]
inc/amd_api_wayland.h [new file with mode: 0644]
inc/amd_app_com.h [new file with mode: 0644]
inc/amd_app_property.h [new file with mode: 0644]
inc/amd_app_status.h [new file with mode: 0644]
inc/amd_appinfo.h [new file with mode: 0644]
inc/amd_config.h [new file with mode: 0644]
inc/amd_cynara.h [new file with mode: 0644]
inc/amd_inotify.h [new file with mode: 0644]
inc/amd_launch.h [new file with mode: 0644]
inc/amd_launchpad.h [new file with mode: 0644]
inc/amd_login_monitor.h [new file with mode: 0644]
inc/amd_noti.h [new file with mode: 0644]
inc/amd_request.h [new file with mode: 0644]
inc/amd_signal.h [new file with mode: 0644]
inc/amd_socket.h [new file with mode: 0644]
inc/amd_suspend.h [new file with mode: 0644]
inc/amd_util.h [new file with mode: 0644]
inc/app_signal.h [new file with mode: 0644]
inc/aul_svc_priv_key.h [new file with mode: 0644]
libamd.pc.in [new file with mode: 0644]
modules/CMakeLists.txt [new file with mode: 0644]
modules/cooldown/CMakeLists.txt [new file with mode: 0644]
modules/cooldown/inc/amd_cooldown.h [new file with mode: 0644]
modules/cooldown/src/amd_cooldown.c [new file with mode: 0644]
modules/cynara-core/CMakeLists.txt [new file with mode: 0644]
modules/cynara-core/inc/amd_cynara_core.h [new file with mode: 0644]
modules/cynara-core/src/amd_cynara_core.c [new file with mode: 0644]
modules/extractor/CMakeLists.txt [new file with mode: 0644]
modules/extractor/inc/amd_extractor.h [new file with mode: 0644]
modules/extractor/src/amd_extractor.c [new file with mode: 0644]
modules/input/CMakeLists.txt [new file with mode: 0644]
modules/input/inc/amd_input.h [new file with mode: 0644]
modules/input/src/amd_input.c [new file with mode: 0644]
modules/launchpad/CMakeLists.txt [new file with mode: 0644]
modules/launchpad/inc/launchpad-private.h [new file with mode: 0644]
modules/launchpad/src/launchpad.c [new file with mode: 0644]
modules/rua/CMakeLists.txt [new file with mode: 0644]
modules/rua/inc/amd_rua.h [new file with mode: 0644]
modules/rua/src/amd_rua.c [new file with mode: 0644]
modules/share/CMakeLists.txt [new file with mode: 0644]
modules/share/inc/amd_share.h [new file with mode: 0644]
modules/share/src/amd_share.c [new file with mode: 0644]
modules/splash-screen/CMakeLists.txt [new file with mode: 0644]
modules/splash-screen/inc/splash-screen-private.h [new file with mode: 0644]
modules/splash-screen/src/splash-screen.c [new file with mode: 0644]
modules/ui-core/CMakeLists.txt [new file with mode: 0644]
modules/ui-core/inc/amd_app_group.h [new file with mode: 0644]
modules/ui-core/inc/amd_screen_connector.h [new file with mode: 0644]
modules/ui-core/src/amd_app_group.c [new file with mode: 0644]
modules/ui-core/src/amd_screen_connector.c [new file with mode: 0644]
modules/ui-core/src/ui_core.c [new file with mode: 0644]
modules/wayland-core/CMakeLists.txt [new file with mode: 0644]
modules/wayland-core/inc/wayland-core-private.h [new file with mode: 0644]
modules/wayland-core/src/wayland-core.c [new file with mode: 0644]
modules/widget/CMakeLists.txt [new file with mode: 0644]
modules/widget/inc/amd_widget.h [new file with mode: 0644]
modules/widget/src/amd_widget.c [new file with mode: 0644]
packaging/ac.conf [new file with mode: 0644]
packaging/ac.service [new file with mode: 0644]
packaging/ac.socket [new file with mode: 0644]
packaging/amd.manifest [new file with mode: 0644]
packaging/amd.spec [new file with mode: 0644]
src/amd/main.c [new file with mode: 0644]
src/lib/amd_api_app_com.c [new file with mode: 0644]
src/lib/amd_api_app_status.c [new file with mode: 0644]
src/lib/amd_api_appinfo.c [new file with mode: 0644]
src/lib/amd_api_cynara.c [new file with mode: 0644]
src/lib/amd_api_inotify.c [new file with mode: 0644]
src/lib/amd_api_launch.c [new file with mode: 0644]
src/lib/amd_api_launch_context.c [new file with mode: 0644]
src/lib/amd_api_launchpad.c [new file with mode: 0644]
src/lib/amd_api_login_monitor.c [new file with mode: 0644]
src/lib/amd_api_noti.c [new file with mode: 0644]
src/lib/amd_api_request.c [new file with mode: 0644]
src/lib/amd_api_signal.c [new file with mode: 0644]
src/lib/amd_api_suspend.c [new file with mode: 0644]
src/lib/amd_api_wayland.c [new file with mode: 0644]
src/lib/amd_app_com.c [new file with mode: 0644]
src/lib/amd_app_property.c [new file with mode: 0644]
src/lib/amd_app_status.c [new file with mode: 0644]
src/lib/amd_appinfo.c [new file with mode: 0644]
src/lib/amd_config.c [new file with mode: 0644]
src/lib/amd_cynara.c [new file with mode: 0644]
src/lib/amd_inotify.c [new file with mode: 0644]
src/lib/amd_launch.c [new file with mode: 0644]
src/lib/amd_launchpad.c [new file with mode: 0644]
src/lib/amd_login_monitor.c [new file with mode: 0644]
src/lib/amd_main.c [new file with mode: 0644]
src/lib/amd_noti.c [new file with mode: 0644]
src/lib/amd_request.c [new file with mode: 0644]
src/lib/amd_signal.c [new file with mode: 0644]
src/lib/amd_socket.c [new file with mode: 0644]
src/lib/amd_suspend.c [new file with mode: 0644]
src/lib/amd_util.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index d4b78ce..064881e 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,20 +1,3 @@
-Authors of GNU Hello.
-
-  Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc.
-
-  Copying and distribution of this file, with or without modification,
-  are permitted in any medium without royalty provided the copyright
-  notice and this notice are preserved.
-
-The following contributions warranted legal paper exchanges with the
-Free Software Foundation.  See also the ChangeLog and THANKS files.
-
-Mike Haertel
-David MacKenzie
-Jan Brittenson
-Roland McGrath
-Charles Hannum
-Bruce Korb             hello.c, configure.ac.
-Karl Eichwalder                all files.
-Karl Berry             all files.
-The King               releases.
+Jayoun Lee <airjany@samsung.com>
+Sewook Park <sewook7.park@samsung.com>
+Jaeho Lee <jaeho81.lee@samsung.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..accb370
--- /dev/null
@@ -0,0 +1,109 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+PROJECT(amd C)
+
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed")
+
+#################################################################
+# Build AMD                                                     #
+#################################################################
+SET(AMD "amd")
+AUX_SOURCE_DIRECTORY(src/amd AMD_SRCS)
+
+INCLUDE(FindPkgConfig)
+
+FOREACH(flag ${AMD_PKGS_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+ADD_EXECUTABLE(${AMD} ${AMD_SRCS})
+SET_TARGET_PROPERTIES(${AMD} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS} -fPIE")
+TARGET_LINK_LIBRARIES(${AMD} ${AMD_PKGS_LDFLAGS} "-pie -ldl")
+INSTALL(TARGETS ${AMD} DESTINATION bin)
+
+#################################################################
+# Build AMD Library                                             #
+#################################################################
+SET(LIB_AMD "libamd")
+AUX_SOURCE_DIRECTORY(src/lib LIB_AMD_SRCS)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/inc)
+SET(HEADERS_LIB_AMD
+       amd.h
+       amd_api_noti.h
+       amd_api_wayland.h
+       amd_api_app_status.h
+       amd_api_appinfo.h
+       amd_api_launch_context.h
+       amd_api_app_com.h
+       amd_api_request.h
+       amd_api_cynara.h
+       amd_api_launch.h
+       amd_api_launchpad.h
+       amd_api_login_monitor.h
+       amd_api_suspend.h
+       amd_api_signal.h
+       amd_api_inotify.h
+       )
+
+INCLUDE(FindPkgConfig)
+
+SET(LIB_AMD_PKG_CHECK_MODULES
+       dlog
+       aul
+       glib-2.0
+       gio-2.0
+       vconf
+       pkgmgr-info
+       pkgmgr
+       bundle
+       libsystemd
+       cert-svc-vcore
+       libtzplatform-config
+       ttrace
+       app2sd
+       capi-network-connection
+       capi-system-info
+       )
+
+PKG_CHECK_MODULES(LIB_AMD_PKGS REQUIRED ${LIB_AMD_PKG_CHECK_MODULES})
+
+FOREACH(flag ${LIB_AMD_PKGS_CFLAGS})
+       SET(EXTRA_CFLAGS_LIB_AMD "${EXTRA_CFLAGS_LIB_AMD} ${flag}")
+ENDFOREACH(flag)
+
+ADD_LIBRARY(${LIB_AMD} SHARED ${LIB_AMD_SRCS})
+SET_TARGET_PROPERTIES(${LIB_AMD} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS_LIB_AMD}")
+SET_TARGET_PROPERTIES(${LIB_AMD} PROPERTIES SOVERSION ${MAJORVER})
+SET_TARGET_PROPERTIES(${LIB_AMD} PROPERTIES VERSION ${FULLVER})
+SET_TARGET_PROPERTIES(${LIB_AMD} PROPERTIES OUTPUT_NAME amd)
+TARGET_LINK_LIBRARIES(${LIB_AMD} ${LIB_AMD_PKGS_LDFLAGS})
+
+CONFIGURE_FILE(${LIB_AMD}.pc.in ${AMD}.pc @ONLY)
+
+INSTALL(TARGETS ${LIB_AMD} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${AMD}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+FOREACH(hfile ${HEADERS_LIB_AMD})
+       INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/inc/${hfile} DESTINATION include/amd)
+ENDFOREACH(hfile)
+
+ADD_CUSTOM_TARGET(${LIB_AMD}.so ALL
+       COMMAND ${CMAKE_COMMAND} -E create_symlink ${LIB_INSTALL_DIR}/${LIB_AMD}.so.${MAJORVER} ${LIB_AMD}.so)
+INSTALL(FILES ${LIB_AMD}.so DESTINATION ${AMD_MODULES_DIR})
+
+ADD_SUBDIRECTORY(modules)
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..a06208b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,204 @@
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
+
diff --git a/inc/amd.h b/inc/amd.h
new file mode 100644 (file)
index 0000000..798c342
--- /dev/null
+++ b/inc/amd.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <amd_api_noti.h>
+#include <amd_api_appinfo.h>
+#include <amd_api_wayland.h>
+#include <amd_api_app_status.h>
+#include <amd_api_launch_context.h>
+#include <amd_api_app_com.h>
+#include <amd_api_request.h>
+#include <amd_api_cynara.h>
+#include <amd_api_launch.h>
+#include <amd_api_launchpad.h>
+#include <amd_api_suspend.h>
+#include <amd_api_login_monitor.h>
+#include <amd_api_signal.h>
+#include <amd_api_inotify.h>
diff --git a/inc/amd_api.h b/inc/amd_api.h
new file mode 100644 (file)
index 0000000..9d2ed3a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef __AMD_API_H__
+#define __AMD_API_H__
+
+#define EXPORT __attribute__ ((visibility("default")))
+#define EXPORT_API EXPORT
+
+#endif /* __AMD_API_H__ */
diff --git a/inc/amd_api_app_com.h b/inc/amd_api_app_com.h
new file mode 100644 (file)
index 0000000..d4378cb
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <bundle.h>
+
+int amd_app_com_send(const char *endpoint, int cpid, bundle *envelope, uid_t uid);
+
diff --git a/inc/amd_api_app_status.h b/inc/amd_api_app_status.h
new file mode 100644 (file)
index 0000000..57dffe4
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <glib.h>
+
+typedef enum {
+       AMD_AT_SERVICE_APP,
+       AMD_AT_UI_APP,
+       AMD_AT_WIDGET_APP,
+       AMD_AT_WATCH_APP,
+} amd_app_type_e;
+
+typedef struct app_status_s *amd_app_status_h;
+typedef void (*amd_app_status_cb)(amd_app_status_h h, void *user_data);
+
+amd_app_status_h amd_app_status_find_by_effective_pid(int pid);
+amd_app_status_h amd_app_status_find_by_pid(int pid);
+amd_app_status_h amd_app_status_find_by_appid(const char *appid, uid_t uid);
+int amd_app_status_get_pid(amd_app_status_h h);
+uid_t amd_app_status_get_uid(amd_app_status_h h);
+int amd_app_status_get_status(amd_app_status_h h);
+bool amd_app_status_is_home_app(amd_app_status_h h);
+int amd_app_status_get_first_caller_pid(amd_app_status_h h);
+const char *amd_app_status_get_appid(amd_app_status_h h);
+const char *amd_app_status_get_pkgid(amd_app_status_h h);
+const char *amd_app_status_get_instance_id(amd_app_status_h h);
+int amd_app_status_foreach_running_info(amd_app_status_cb callback,
+               void *user_data);
+int amd_app_status_terminate_apps(const char *appid, uid_t uid);
+bool amd_app_status_is_starting(amd_app_status_h h);
+int amd_app_status_get_app_type(amd_app_status_h app_status);
+int amd_app_status_set_extra(amd_app_status_h app_status, const char *key, void *data);
+int amd_app_status_remove_extra(amd_app_status_h app_status, const char *key);
+void *amd_app_status_get_extra(amd_app_status_h app_status, const char *key);
+
+int amd_app_status_get_leader_pid(amd_app_status_h app_status);
+int amd_app_status_set_leader_pid(amd_app_status_h app_status, int pid);
+int amd_app_status_get_fg_cnt(amd_app_status_h app_status);
+int amd_app_status_get_timestamp(amd_app_status_h app_status);
+int amd_app_status_term_bg_apps(GCompareFunc func);
+bool amd_app_status_get_bg_launch(amd_app_status_h app_status);
+amd_app_status_h amd_app_status_find_by_instance_id(const char *appid,
+               const char *instance_id, uid_t uid);
+void amd_app_status_find_service_apps(amd_app_status_h app_status, int status,
+               void (*send_event_to_svc_core)(int, uid_t), bool suspend);
+int amd_app_status_get_process_cnt(const char *appid);
+const char *amd_app_status_get_app_path(amd_app_status_h app_status);
+
diff --git a/inc/amd_api_appinfo.h b/inc/amd_api_appinfo.h
new file mode 100644 (file)
index 0000000..84fba5f
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+typedef enum _amd_appinfo_type {
+       AMD_AIT_NAME = 0,
+       AMD_AIT_EXEC,
+       AMD_AIT_PKGTYPE,
+       AMD_AIT_ONBOOT, /* start on boot: boolean */
+       AMD_AIT_RESTART, /* auto restart: boolean */
+       AMD_AIT_MULTI,
+       AMD_AIT_HWACC,
+       AMD_AIT_PERM,
+       AMD_AIT_PKGID,
+       AMD_AIT_PRELOAD,
+       AMD_AIT_STATUS,
+       AMD_AIT_POOL,
+       AMD_AIT_COMPTYPE,
+       AMD_AIT_TEP,
+       AMD_AIT_MOUNTABLE_PKG,
+       AMD_AIT_STORAGE_TYPE,
+       AMD_AIT_BG_CATEGORY,
+       AMD_AIT_LAUNCH_MODE,
+       AMD_AIT_GLOBAL,
+       AMD_AIT_EFFECTIVE_APPID,
+       AMD_AIT_TASKMANAGE,
+       AMD_AIT_VISIBILITY,
+       AMD_AIT_APPTYPE,
+       AMD_AIT_ROOT_PATH,
+       AMD_AIT_SPLASH_SCREEN,
+       AMD_AIT_SPLASH_SCREEN_DISPLAY,
+       AMD_AIT_API_VERSION,
+       AMD_AIT_ENABLEMENT,
+       AMD_AIT_COOLDOWN,
+       AMD_AIT_SYSTEM,
+       AMD_AIT_IME,
+       AMD_AIT_MAX
+} amd_appinfo_type;
+
+typedef struct appinfo *amd_appinfo_h;
+typedef struct appinfo_splash_image *amd_appinfo_splash_image_h;
+
+#define APP_TYPE_SERVICE       "svcapp"
+#define APP_TYPE_UI            "uiapp"
+#define APP_TYPE_WIDGET                "widgetapp"
+#define APP_TYPE_WATCH         "watchapp"
+
+#define APP_ENABLEMENT_MASK_ACTIVE      0x1
+
+typedef void (*amd_appinfo_iter_callback)(void *user_data,
+               const char *filename, amd_appinfo_h h);
+int amd_appinfo_insert(uid_t uid, const char *pkgid);
+amd_appinfo_h amd_appinfo_find(uid_t caller_uid, const char *appid);
+const char *amd_appinfo_get_value(amd_appinfo_h h, amd_appinfo_type type);
+const void *amd_appinfo_get_ptr_value(amd_appinfo_h h, amd_appinfo_type type);
+int amd_appinfo_get_int_value(amd_appinfo_h h, amd_appinfo_type type, int *val);
+int amd_appinfo_get_boolean(amd_appinfo_h h, amd_appinfo_type type, bool *val);
+int amd_appinfo_set_value(amd_appinfo_h h, amd_appinfo_type type,
+               const char *val);
+int amd_appinfo_set_ptr_value(amd_appinfo_h h, amd_appinfo_type type,
+               void *val);
+int amd_appinfo_set_int_value(amd_appinfo_h h, amd_appinfo_type type, int val);
+void amd_appinfo_foreach(uid_t uid, amd_appinfo_iter_callback cb,
+               void *user_data);
+int amd_appinfo_load(uid_t uid);
+void amd_appinfo_unload(uid_t uid);
+amd_appinfo_splash_image_h amd_appinfo_find_splash_image(amd_appinfo_h h,
+               const char *name, bool landscape);
+const char *amd_appinfo_splash_image_get_source(amd_appinfo_splash_image_h h);
+const char *amd_appinfo_splash_image_get_type(amd_appinfo_splash_image_h h);
+int amd_appinfo_splash_image_get_indicator_display(
+               amd_appinfo_splash_image_h h);
+int amd_appinfo_splash_image_get_color_depth(amd_appinfo_splash_image_h h);
diff --git a/inc/amd_api_cynara.h b/inc/amd_api_cynara.h
new file mode 100644 (file)
index 0000000..cef5f31
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <amd_api_request.h>
+
+#define PRIVILEGE_WIDGET_VIEWER \
+       "http://tizen.org/privilege/widget.viewer"
+#define PRIVILEGE_APPMANAGER_LAUNCH \
+       "http://tizen.org/privilege/appmanager.launch"
+#define PRIVILEGE_APPMANAGER_KILL \
+       "http://tizen.org/privilege/appmanager.kill"
+#define PRIVILEGE_APPMANAGER_KILL_BGAPP \
+       "http://tizen.org/privilege/appmanager.kill.bgapp"
+#define PRIVILEGE_DOWNLOAD \
+       "http://tizen.org/privilege/download"
+#define PRIVILEGE_CALL \
+       "http://tizen.org/privilege/call"
+#define PRIVILEGE_SYSTEM_SETTING \
+       "http://tizen.org/privilege/systemsettings.admin"
+#define PRIVILEGE_PLATFORM \
+       "http://tizen.org/privilege/internal/default/platform"
+
+enum amd_cynara_result {
+       AMD_CYNARA_RET_ERROR = -2,
+       AMD_CYNARA_RET_DENIED,
+       AMD_CYNARA_RET_ALLOWED,
+       AMD_CYNARA_RET_UNKNOWN,
+       AMD_CYNARA_RET_CONTINUE,
+};
+
+typedef struct caller_info *amd_cynara_caller_info_h;
+
+typedef int (*amd_cynara_checker_func)(amd_cynara_caller_info_h info, amd_request_h req,
+               void *data);
+typedef int (*amd_cynara_sub_checker_func)(amd_cynara_caller_info_h info, amd_request_h req);
+
+typedef struct _amd_cynara_checker {
+       int cmd;
+       amd_cynara_checker_func checker;
+       void *data;
+       int priority;
+} amd_cynara_checker;
+
+typedef void (*amd_cynara_response_cb)(enum amd_cynara_result res, amd_request_h request);
+
+typedef struct _amd_cynara_ops {
+       int (*register_checkers)(const amd_cynara_checker *checkers, int cnt);
+       int (*sub_checker_add)(const char *name, amd_cynara_sub_checker_func func);
+       int (*sub_checker_check)(const char *name, amd_cynara_caller_info_h info, amd_request_h req);
+
+       int (*check_async)(amd_request_h req, amd_cynara_response_cb callback);
+       int (*check)(amd_cynara_caller_info_h info, amd_request_h req, void *data);
+} amd_cynara_ops;
+
+typedef struct _amd_cynara_caller_info_ops {
+       const char *(*get_client)(amd_cynara_caller_info_h info);
+} amd_cynara_caller_info_ops;
+
+int amd_cynara_check_privilege(amd_request_h req, amd_cynara_response_cb callback);
+int amd_cynara_register_checkers(const amd_cynara_checker *checkers, int cnt);
+int amd_cynara_simple_checker(amd_cynara_caller_info_h info, amd_request_h req, void *data);
+const char *amd_cynara_caller_info_get_client(amd_cynara_caller_info_h info);
+int amd_cynara_sub_checker_add(const char *name, amd_cynara_sub_checker_func func);
+int amd_cynara_sub_checker_check(const char *name, amd_cynara_caller_info_h info, amd_request_h req);
+int amd_cynara_register_ops(amd_cynara_ops ops, amd_cynara_caller_info_ops ci_ops);
+
diff --git a/inc/amd_api_inotify.h b/inc/amd_api_inotify.h
new file mode 100644 (file)
index 0000000..db17549
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <sys/inotify.h>
+
+typedef bool (*amd_inotify_watch_cb)(const char *event_name, void *data);
+
+int amd_inotify_add_watch(const char *path, uint32_t mask,
+               amd_inotify_watch_cb callback, void *data);
+void amd_inotify_rm_watch(int wd);
diff --git a/inc/amd_api_launch.h b/inc/amd_api_launch.h
new file mode 100644 (file)
index 0000000..f4ea323
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <amd_api_request.h>
+
+int amd_launch_start_app(const char *appid, amd_request_h req, bool *pending,
+               bool *bg_launch, bool new_instance);
+int amd_launch_term_sub_app(int pid, uid_t uid);
+int amd_launch_start_onboot_apps(uid_t uid);
diff --git a/inc/amd_api_launch_context.h b/inc/amd_api_launch_context.h
new file mode 100644 (file)
index 0000000..6895921
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <amd_api_appinfo.h>
+#include <amd_api_app_status.h>
+
+typedef struct launch_s *amd_launch_context_h;
+
+amd_appinfo_h amd_launch_context_get_appinfo(amd_launch_context_h h);
+const char *amd_launch_context_get_appid(amd_launch_context_h h);
+const char *amd_launch_context_get_instance_id(amd_launch_context_h h);
+int amd_launch_context_get_pid(amd_launch_context_h h);
+bool amd_launch_context_is_subapp(amd_launch_context_h h);
+bool amd_launch_context_is_bg_launch(amd_launch_context_h h);
+int amd_launch_context_set_pid(amd_launch_context_h h, int pid);
+bool amd_launch_context_is_new_instance(amd_launch_context_h h);
+int amd_launch_context_set_subapp(amd_launch_context_h h, bool is_subapp);
+int amd_launch_context_set_app_status(amd_launch_context_h h, amd_app_status_h status);
+
diff --git a/inc/amd_api_launchpad.h b/inc/amd_api_launchpad.h
new file mode 100644 (file)
index 0000000..219b828
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <bundle.h>
+
+typedef int (*amd_launcher_cb)(bundle *b, uid_t uid, void *user_data);
+
+int amd_launchpad_set_launcher(amd_launcher_cb launcher, void *user_data);
diff --git a/inc/amd_api_login_monitor.h b/inc/amd_api_login_monitor.h
new file mode 100644 (file)
index 0000000..9d62c21
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <sys/types.h>
+
+typedef enum amd_uid_state_e {
+       AMD_UID_STATE_UNKNOWN = 0x00,
+       AMD_UID_STATE_OPENING = 0x01,
+       AMD_UID_STATE_LINGERING = 0x02,
+       AMD_UID_STATE_ONLINE = 0x04,
+       AMD_UID_STATE_ACTIVE = 0x08,
+       AMD_UID_STATE_CLOSING = 0x10,
+       AMD_UID_STATE_OFFLINE = 0x20,
+} amd_uid_state;
+
+int amd_login_monitor_get_uids(uid_t **uids);
+amd_uid_state amd_login_monitor_get_uid_state(uid_t uid);
diff --git a/inc/amd_api_noti.h b/inc/amd_api_noti.h
new file mode 100644 (file)
index 0000000..7b01b47
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <bundle.h>
+
+#define AMD_NOTI_CONTINUE      0
+#define AMD_NOTI_STOP  -2
+
+typedef int (*amd_noti_cb)(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data);
+
+int amd_noti_send(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data);
+int amd_noti_listen(const char *msg, amd_noti_cb callback);
+
diff --git a/inc/amd_api_request.h b/inc/amd_api_request.h
new file mode 100644 (file)
index 0000000..10083fd
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <bundle.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+typedef struct request_s *amd_request_h;
+typedef int (*amd_request_cmd_dispatch_cb)(amd_request_h req);
+typedef struct _amd_request_cmd_dispatch {
+       int cmd;
+       amd_request_cmd_dispatch_cb callback;
+} amd_request_cmd_dispatch;
+
+typedef void* amd_request_reply_h;
+
+int amd_request_send_result(amd_request_h req, int res);
+int amd_request_send_raw(amd_request_h req, int cmd, unsigned char *data, int len);
+int amd_request_get_fd(amd_request_h req);
+int amd_request_get_pid(amd_request_h req);
+int amd_request_get_cmd(amd_request_h req);
+int amd_request_set_cmd(amd_request_h req, int cmd);
+bundle *amd_request_get_bundle(amd_request_h req);
+amd_request_h amd_request_create_local(int cmd, uid_t uid, int pid, bundle *kb);
+void amd_request_free_local(amd_request_h req);
+int amd_request_remove_fd(amd_request_h req);
+int amd_request_reply_for_pending_request(int pid);
+int amd_request_flush_pending_request(int pid);
+uid_t amd_request_get_target_uid(amd_request_h req);
+uid_t amd_request_get_uid(amd_request_h req);
+pid_t amd_request_get_target_pid(amd_request_h req);
+int amd_request_usr_init(uid_t uid);
+int amd_request_register_cmds(const amd_request_cmd_dispatch *cmds, int cnt);
+int amd_request_reply_append(int pid, void *reply);
+int amd_request_reply_remove(int pid, void *reply);
+amd_request_reply_h amd_request_reply_create_full(amd_request_h req,
+               pid_t pid, int result, int cmd, void *extra,
+               void (*extra_free_cb)(void *data));
+int amd_request_reply_foreach_extra(int pid, int (*callback)(void *data));
+int amd_request_get_len(amd_request_h req);
+unsigned char *amd_request_get_raw(amd_request_h req);
+GTimeVal *amd_request_get_start_time(amd_request_h req);
+
diff --git a/inc/amd_api_signal.h b/inc/amd_api_signal.h
new file mode 100644 (file)
index 0000000..eab6ec7
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+int amd_signal_send_tep_mount(char *mnt_path[], const char *pkgid);
+int amd_signal_send_tep_unmount(const char *mnt_path);
diff --git a/inc/amd_api_suspend.h b/inc/amd_api_suspend.h
new file mode 100644 (file)
index 0000000..336969e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <amd_api_appinfo.h>
+
+#define AMD_SUSPEND_TYPE_EXCLUDE "exclude"
+#define AMD_SUSPEND_TYPE_INCLUDE "include"
+
+enum amd_suspend_status_e {
+       AMD_SUSPEND_STATUS_EXCLUDE,
+       AMD_SUSPEND_STATUS_INCLUDE,
+};
+
+enum amd_background_category_e {
+       AMD_BACKGROUND_CATEGORY_MEDIA = 0x01,
+       AMD_BACKGROUND_CATEGORY_DOWNLOAD = 0x02,
+       AMD_BACKGROUND_CATEGORY_BACKGROUND_NETWORK = 0x04,
+       AMD_BACKGROUND_CATEGORY_LOCATION = 0x08,
+       AMD_BACKGROUND_CATEGORY_SENSOR = 0x10,
+       AMD_BACKGROUND_CATEGORY_IOT_COMMUNICATION = 0x20,
+       AMD_BACKGROUND_CATEGORY_SYSTEM = 0x40
+};
+
+bool amd_suspend_is_allowed_background(amd_appinfo_h ai);
+void amd_suspend_add_timer(int pid);
+void amd_suspend_remove_timer(int pid);
+int amd_suspend_add_proc(int pid);
+int amd_suspend_remove_proc(int pid);
+int amd_suspend_update_status(int pid, int status);
diff --git a/inc/amd_api_wayland.h b/inc/amd_api_wayland.h
new file mode 100644 (file)
index 0000000..082ef8c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+void *amd_wayland_get_display(void);
+void amd_wayland_set_display(void *display);
+void *amd_wayland_get_tizen_policy(void);
+void amd_wayland_set_tizen_policy(void *tizen_policy);
diff --git a/inc/amd_app_com.h b/inc/amd_app_com.h
new file mode 100644 (file)
index 0000000..3fbc502
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef __AMD_APP_COM_H__
+#define __AMD_APP_COM_H__
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <bundle.h>
+
+int _app_com_broker_init(void);
+int _app_com_broker_fini(void);
+int _app_com_client_remove(int cpid);
+int _app_com_join(const char *endpoint, int cpid, const char *filter,
+               uid_t uid);
+int _app_com_send(const char *endpoint, int cpid, bundle *envelope, uid_t uid);
+const char *_app_com_get_privilege(const char *endpoint);
+bool _app_com_endpoint_exists(const char *endpoint);
+
+#endif /* __AMD_APP_COM_H__ */
diff --git a/inc/amd_app_property.h b/inc/amd_app_property.h
new file mode 100644 (file)
index 0000000..b573dd1
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <glib.h>
+
+#define METADATA_LARGEMEMORY "http://tizen.org/metadata/largememory"
+#define METADATA_OOMTERMINATION "http://tizen.org/metadata/oomtermination"
+
+typedef struct app_property_s *app_property_h;
+
+int _app_property_add_alias_info(app_property_h app_property,
+               const char *alias_appid, const char *appid);
+int _app_property_remove_alias_info(app_property_h app_property,
+               const char *alias_appid, const char *appid);
+const char *_app_property_get_real_appid(app_property_h app_property,
+               const char *alias_appid);
+GList *_app_property_get_allowed_app_list(app_property_h app_property,
+               const char *appid);
+app_property_h _app_property_find(uid_t uid);
+int _app_property_insert(uid_t uid, const char *appid);
+int _app_property_delete(uid_t uid, const char *appid);
+int _app_property_load(uid_t uid);
+void _app_property_unload(uid_t uid);
+int _app_property_init(void);
+void _app_property_fini(void);
+void _app_property_cache_invalidate(app_property_h app_property);
+bool _app_property_metadata_query_bool(app_property_h app_property,
+               const char *appid, const char *key);
+int _app_property_metadata_foreach(app_property_h app_property,
+               const char *appid, const char *key,
+               int (*callback)(const char *value, void *data),
+               void *user_data);
+bool _app_property_metadata_match(app_property_h app_property,
+               const char *appid, const char *key, const char *value);
+bool _app_property_metadata_query_activation(app_property_h app_property,
+               const char *appid, const char *key);
diff --git a/inc/amd_app_status.h b/inc/amd_app_status.h
new file mode 100644 (file)
index 0000000..3f74de2
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <stdbool.h>
+
+#include "amd_appinfo.h"
+
+typedef enum {
+       AT_SERVICE_APP,
+       AT_UI_APP,
+       AT_WIDGET_APP,
+       AT_WATCH_APP,
+} app_type_e;
+
+typedef struct app_status_s *app_status_h;
+
+int _app_status_set_extra(app_status_h app_status, const char *key, void *data);
+int _app_status_remove_extra(app_status_h app_status, const char *key);
+void *_app_status_get_extra(app_status_h app_status, const char *key);
+int _app_status_add_app_info(const struct appinfo *ai, int pid,
+               bool is_subapp, uid_t uid, int caller_pid,
+               bool bg_launch, const char *instance_id,
+               bool debug_mode);
+int _app_status_remove_all_app_info_with_uid(uid_t uid);
+int _app_status_remove(app_status_h app_status);
+int _app_status_update_status(app_status_h app_status, int status, bool force,
+               bool update_group_info);
+int _app_status_update_last_caller_pid(app_status_h app_status, int caller_pid);
+int _app_status_update_bg_launch(app_status_h app_status, bool bg_launch);
+int _app_status_get_process_cnt(const char *appid);
+bool _app_status_is_home_app(app_status_h app_status);
+int _app_status_get_pid(app_status_h app_status);
+int _app_status_get_last_caller_pid(app_status_h app_status);
+int _app_status_is_running(app_status_h app_status);
+int _app_status_get_status(app_status_h app_status);
+uid_t _app_status_get_uid(app_status_h app_status);
+const char *_app_status_get_appid(app_status_h app_status);
+const char *_app_status_get_pkgid(app_status_h app_status);
+int _app_status_get_leader_pid(app_status_h app_status);
+int _app_status_set_leader_pid(app_status_h app_status, int pid);
+int _app_status_get_fg_cnt(app_status_h app_status);
+int _app_status_get_timestamp(app_status_h app_status);
+int _app_status_term_bg_apps(GCompareFunc func);
+bool _app_status_get_bg_launch(app_status_h app_status);
+const char *_app_status_get_instance_id(app_status_h app_stauts);
+int _app_status_get_app_type(app_status_h app_status);
+bool _app_status_socket_exists(app_status_h app_status);
+bool _app_status_is_starting(app_status_h app_status);
+int _app_status_update_is_starting(app_status_h app_status, bool is_starting);
+const char *_app_status_get_app_path(app_status_h app_status);
+app_status_h _app_status_find(int pid);
+app_status_h _app_status_find_v2(int pid);
+app_status_h _app_status_find_by_appid(const char *appid, uid_t uid);
+app_status_h _app_status_find_by_appid_v2(const char *appid, uid_t uid);
+app_status_h _app_status_find_with_org_caller(const char *appid, uid_t uid,
+               int caller_pid);
+app_status_h _app_status_find_by_instance_id(const char *appid,
+               const char *instance_id, uid_t uid);
+void _app_status_find_service_apps(app_status_h app_status, int status,
+               void (*send_event_to_svc_core)(int, uid_t), bool suspend);
+void _app_status_check_service_only(app_status_h app_status,
+               void (*send_event_to_svc_core)(int, uid_t));
+int _app_status_send_running_appinfo(int fd, int cmd, uid_t uid);
+int _app_status_foreach_running_appinfo(void (*callback)(app_status_h, void *),
+               void *data);
+int _app_status_terminate_apps(const char *appid, uid_t uid);
+int _app_status_terminate_apps_by_pkgid(const char *pkgid, uid_t uid);
+int _app_status_get_appid_bypid(int fd, int pid);
+int _app_status_get_pkgid_bypid(int fd, int pid);
+int _app_status_get_instance_id_bypid(int fd, int pid);
+int _app_status_get_org_caller_pid(app_status_h app_status);
+int _app_status_publish_status(int pid, int context_status);
+void _app_status_cleanup(app_status_h app_status);
+int _app_status_usr_init(uid_t uid);
+void _app_status_usr_fini(uid_t uid);
+int _app_status_init(void);
+int _app_status_finish(void);
diff --git a/inc/amd_appinfo.h b/inc/amd_appinfo.h
new file mode 100644 (file)
index 0000000..630f6cf
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include <glib.h>
+#include <stdbool.h>
+
+#define AIT_START 0
+enum appinfo_type {
+       AIT_NAME = AIT_START,
+       AIT_EXEC,
+       AIT_PKGTYPE,
+       AIT_ONBOOT, /* start on boot: boolean */
+       AIT_RESTART, /* auto restart: boolean */
+       AIT_MULTI,
+       AIT_HWACC,
+       AIT_PERM,
+       AIT_PKGID,
+       AIT_PRELOAD,
+       AIT_STATUS,
+       AIT_POOL,
+       AIT_COMPTYPE,
+       AIT_TEP,
+       AIT_MOUNTABLE_PKG,
+       AIT_STORAGE_TYPE,
+       AIT_BG_CATEGORY,
+       AIT_LAUNCH_MODE,
+       AIT_GLOBAL,
+       AIT_EFFECTIVE_APPID,
+       AIT_TASKMANAGE,
+       AIT_VISIBILITY,
+       AIT_APPTYPE,
+       AIT_ROOT_PATH,
+       AIT_SPLASH_SCREEN,
+       AIT_SPLASH_SCREEN_DISPLAY,
+       AIT_API_VERSION,
+       AIT_ENABLEMENT,
+       AIT_COOLDOWN,
+       AIT_SYSTEM,
+       AIT_IME,
+       AIT_MAX
+};
+
+struct appinfo {
+       char *val[AIT_MAX];
+};
+
+struct appinfo_splash_screen {
+       GHashTable *portrait;
+       GHashTable *landscape;
+};
+
+struct appinfo_splash_image {
+       char *src;
+       char *type;
+       char *indicatordisplay;
+       char *color_depth;
+};
+
+#define APP_TYPE_SERVICE       "svcapp"
+#define APP_TYPE_UI            "uiapp"
+#define APP_TYPE_WIDGET                "widgetapp"
+#define APP_TYPE_WATCH         "watchapp"
+
+#define APP_ENABLEMENT_MASK_ACTIVE     0x1
+#define APP_ENABLEMENT_MASK_REQUEST    0x2
+
+typedef void (*appinfo_iter_callback)(void *user_data,
+               const char *filename, struct appinfo *c);
+int _appinfo_init(void);
+void _appinfo_fini(void);
+int _appinfo_insert(uid_t uid, const char *pkgid);
+struct appinfo *_appinfo_find(uid_t caller_uid, const char *appid);
+const char *_appinfo_get_value(const struct appinfo *c, enum appinfo_type type);
+const void *_appinfo_get_ptr_value(const struct appinfo *c,
+               enum appinfo_type type);
+int _appinfo_get_int_value(const struct appinfo *c, enum appinfo_type type,
+               int *val);
+int _appinfo_get_boolean(const struct appinfo *c, enum appinfo_type type,
+                       bool *val);
+int _appinfo_set_value(struct appinfo *c, enum appinfo_type, const char *val);
+int _appinfo_set_ptr_value(struct appinfo *c, enum appinfo_type, void *val);
+int _appinfo_set_int_value(struct appinfo *c, enum appinfo_type type, int val);
+void _appinfo_foreach(uid_t uid, appinfo_iter_callback cb, void *user_data);
+int _appinfo_load(uid_t uid);
+void _appinfo_unload(uid_t uid);
+struct appinfo_splash_image *_appinfo_find_splash_image(struct appinfo *c,
+               const char *name, bool landscape);
+const char *_appinfo_splash_image_get_source(struct appinfo_splash_image *s);
+const char *_appinfo_splash_image_get_type(struct appinfo_splash_image *s);
+int _appinfo_splash_image_get_indicator_display(struct appinfo_splash_image *s);
+int _appinfo_splash_image_get_color_depth(struct appinfo_splash_image *s);
diff --git a/inc/amd_config.h b/inc/amd_config.h
new file mode 100644 (file)
index 0000000..2826170
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef __AMD_CONFIG_H__
+#define __AMD_CONFIG_H__
+
+typedef enum {
+       TIZEN_PROFILE_UNKNOWN = 0,
+       TIZEN_PROFILE_MOBILE = 0x1,
+       TIZEN_PROFILE_WEARABLE = 0x2,
+       TIZEN_PROFILE_TV = 0x4,
+       TIZEN_PROFILE_IVI = 0x8,
+       TIZEN_PROFILE_COMMON = 0x10,
+} tizen_profile_t;
+
+tizen_profile_t _get_tizen_profile(void);
+
+#define TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP \
+       (!(_get_tizen_profile() & (TIZEN_PROFILE_TV)))
+#define TIZEN_FEATURE_BLOCK_INPUT \
+       (!(_get_tizen_profile() & (TIZEN_PROFILE_TV | TIZEN_PROFILE_IVI)))
+#define TIZEN_FEATURE_AUTO_ROTATION \
+       (!(_get_tizen_profile() & (TIZEN_PROFILE_TV | TIZEN_PROFILE_IVI)))
+
+#endif /* __AMD_CONFIG_H__ */
diff --git a/inc/amd_cynara.h b/inc/amd_cynara.h
new file mode 100644 (file)
index 0000000..638e1b4
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "amd_request.h"
+
+#define SYSPOPUP_NAME "_INTERNAL_SYSPOPUP_NAME_"
+#define PRIVILEGE_WIDGET_VIEWER \
+       "http://tizen.org/privilege/widget.viewer"
+#define PRIVILEGE_APPMANAGER_LAUNCH \
+       "http://tizen.org/privilege/appmanager.launch"
+#define PRIVILEGE_APPMANAGER_KILL \
+       "http://tizen.org/privilege/appmanager.kill"
+#define PRIVILEGE_APPMANAGER_KILL_BGAPP \
+       "http://tizen.org/privilege/appmanager.kill.bgapp"
+#define PRIVILEGE_DOWNLOAD \
+       "http://tizen.org/privilege/download"
+#define PRIVILEGE_CALL \
+       "http://tizen.org/privilege/call"
+#define PRIVILEGE_SYSTEM_SETTING \
+       "http://tizen.org/privilege/systemsettings.admin"
+#define PRIVILEGE_PLATFORM \
+       "http://tizen.org/privilege/internal/default/platform"
+
+enum amd_cynara_res {
+       AMD_CYNARA_ERROR = -2,
+       AMD_CYNARA_DENIED,
+       AMD_CYNARA_ALLOWED,
+       AMD_CYNARA_UNKNOWN,
+       AMD_CYNARA_CONTINUE,
+};
+
+typedef struct caller_info *caller_info_h;
+
+typedef int (*checker_func)(caller_info_h info, request_h req,
+               void *data);
+typedef int (*sub_checker_func)(caller_info_h info, request_h req);
+
+typedef struct _cynara_checker {
+       int cmd;
+       checker_func checker;
+       void *data;
+       int priority;
+} cynara_checker;
+
+typedef void (*cynara_response_cb)(enum amd_cynara_res res, request_h request);
+
+typedef struct _cynara_ops {
+       int (*register_checkers)(const cynara_checker *checkers, int cnt);
+       int (*sub_checker_add)(const char *name, sub_checker_func func);
+       int (*sub_checker_check)(const char *name, caller_info_h info, request_h req);
+
+       int (*check_async)(request_h req, cynara_response_cb callback);
+       int (*check)(caller_info_h info, request_h req, void *data);
+} cynara_ops;
+
+typedef struct _cynara_caller_info_ops {
+       const char *(*get_client)(caller_info_h info);
+} cynara_caller_info_ops;
+
+int _cynara_init(void);
+void _cynara_finish(void);
+int _cynara_check_privilege(request_h req, cynara_response_cb callback);
+int _cynara_register_checkers(const cynara_checker *checkers, int cnt);
+int _cynara_simple_checker(caller_info_h info, request_h req, void *data);
+const char *_cynara_caller_info_get_client(caller_info_h info);
+int _cynara_sub_checker_add(const char *name, sub_checker_func func);
+int _cynara_sub_checker_check(const char *name, caller_info_h info, request_h req);
+int _cynara_register_ops(cynara_ops ops, cynara_caller_info_ops ci_ops);
+
diff --git a/inc/amd_inotify.h b/inc/amd_inotify.h
new file mode 100644 (file)
index 0000000..8db8bc7
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <sys/inotify.h>
+
+typedef bool (*inotify_watch_cb)(const char *event_name, void *data);
+
+int _inotify_add_watch(const char *path, uint32_t mask,
+               inotify_watch_cb callback, void *data);
+void _inotify_rm_watch(int wd);
+int _inotify_init(void);
+void _inotify_fini(void);
diff --git a/inc/amd_launch.h b/inc/amd_launch.h
new file mode 100644 (file)
index 0000000..04b5c43
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <bundle.h>
+
+#include "amd_request.h"
+#include "amd_util.h"
+#include "amd_appinfo.h"
+#include "amd_app_status.h"
+
+#define PROC_STATUS_LAUNCH 0
+#define PROC_STATUS_FG 3
+#define PROC_STATUS_BG 4
+#define PROC_STATUS_FOCUS 5
+#define PROC_STATUS_HIDE 7
+
+typedef struct launch_s *launch_h;
+
+int _send_to_sigkill(int pid);
+int _resume_app(int pid, request_h req);
+int _pause_app(int pid, request_h req);
+int _term_app(int pid, request_h req);
+int _term_req_app(int pid, request_h req);
+int _term_bgapp(int pid, request_h req);
+int _term_sub_app(int pid, uid_t uid);
+int _launch_start_app(const char *appid, request_h req, bool *pending,
+               bool *bg_launch, bool new_instance);
+int _launch_start_app_local(uid_t uid, const char *appid);
+int _launch_start_app_local_with_bundle(uid_t uid, const char *appid,
+               bundle *kb);
+int _launch_start_onboot_app_local(uid_t uid, const char *appid,
+               struct appinfo *ai);
+int _launch_init(void);
+void _launch_set_focused_pid(int pid);
+int _launch_get_focused_pid(void);
+int _term_app_v2(int pid, request_h req, bool *pend);
+int _launch_start_onboot_apps(uid_t uid);
+int _terminate_app_local(uid_t uid, int pid);
+int _launch_context_get_pid(launch_h h);
+int _launch_context_set_pid(launch_h h, int pid);
+const char *_launch_context_get_appid(launch_h h);
+bool _launch_context_is_new_instance(launch_h h);
+int _launch_context_set_subapp(launch_h h, bool is_subapp);
+int _launch_context_set_app_status(launch_h h, app_status_h status);
+const char *_launch_context_get_instance_id(launch_h h);
+bool _launch_context_is_subapp(launch_h h);
+bool _launch_context_is_bg_launch(launch_h h);
+const struct appinfo *_launch_context_get_appinfo(launch_h h);
+
+
diff --git a/inc/amd_launchpad.h b/inc/amd_launchpad.h
new file mode 100644 (file)
index 0000000..37c7bff
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <bundle.h>
+
+int _launchpad_set_launcher(int (*callback)(bundle *, uid_t, void *),
+               void *user_data);
+int _launchpad_launch(bundle *kb, uid_t uid);
diff --git a/inc/amd_login_monitor.h b/inc/amd_login_monitor.h
new file mode 100644 (file)
index 0000000..9f411bc
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef __AMD_LOGIN_MONITOR_H__
+#define __AMD_LOGIN_MOINTOR_H__
+
+#include <unistd.h>
+#include <sys/types.h>
+
+typedef enum uid_state_e {
+       UID_STATE_UNKNOWN = 0x00,
+       UID_STATE_OPENING = 0x01,
+       UID_STATE_LINGERING = 0x02,
+       UID_STATE_ONLINE = 0x04,
+       UID_STATE_ACTIVE = 0x08,
+       UID_STATE_CLOSING = 0x10,
+       UID_STATE_OFFLINE = 0x20,
+} uid_state;
+
+void _login_monitor_set_uid_state(uid_t uid, uid_state state);
+uid_state _login_monitor_get_uid_state(uid_t uid);
+int _login_monitor_get_uids(uid_t **uids);
+int _login_monitor_init(void);
+void _login_monitor_fini(void);
+
+#endif /* __AMD_LOGIN_MONITOR_H__ */
diff --git a/inc/amd_noti.h b/inc/amd_noti.h
new file mode 100644 (file)
index 0000000..c45b7fe
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <bundle.h>
+
+#define NOTI_CONTINUE  0
+#define NOTI_STOP      -2
+
+typedef int (*noti_cb)(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data);
+
+int _noti_send(const char *msg, int arg1, int arg2, void *arg3, bundle *data);
+int _noti_listen(const char *msg, noti_cb callback);
+int _noti_init(void);
+void _noti_fini(void);
diff --git a/inc/amd_request.h b/inc/amd_request.h
new file mode 100644 (file)
index 0000000..2654b76
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <bundle.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+typedef struct request_s *request_h;
+typedef int (*request_cmd_dispatch_cb)(request_h req);
+typedef struct _request_cmd_dispatch {
+       int cmd;
+       request_cmd_dispatch_cb callback;
+} request_cmd_dispatch;
+
+typedef void* request_reply_h;
+
+int _request_send_result(request_h req, int res);
+int _request_send_raw(request_h req, int cmd, unsigned char *data, int len);
+int _request_get_fd(request_h req);
+int _request_get_pid(request_h req);
+int _request_get_cmd(request_h req);
+int _request_set_cmd(request_h req, int cmd);
+bundle *_request_get_bundle(request_h req);
+request_h _request_create_local(int cmd, uid_t uid, int pid, bundle *kb);
+void _request_free_local(request_h req);
+int _request_remove_fd(request_h req);
+int _request_reply_for_pending_request(int pid);
+int _request_flush_pending_request(int pid);
+uid_t _request_get_target_uid(request_h req);
+uid_t _request_get_uid(request_h req);
+pid_t _request_get_target_pid(request_h req);
+int _request_usr_init(uid_t uid);
+int _request_register_cmds(const request_cmd_dispatch *cmds, int cnt);
+int _request_init(void);
+void _request_fini(void);
+int _request_reply_reset_pending_timer(request_h req, unsigned int interval, int pid);
+int _request_reply_append(int pid, void *reply);
+int _request_reply_remove(int pid, void *reply);
+request_reply_h _request_reply_create_full(request_h req, pid_t pid, int result,
+               int cmd, void *extra, void (*extra_free_cb)(void *data));
+int _request_reply_foreach_extra(int pid, int (*callback)(void *data));
+int _request_get_len(request_h req);
+unsigned char *_request_get_raw(request_h req);
+GTimeVal *_request_get_start_time(request_h req);
diff --git a/inc/amd_signal.h b/inc/amd_signal.h
new file mode 100644 (file)
index 0000000..4d6cd06
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#define APP_BOOSTING_PERIOD 1500
+#define APP_BOOSTING_STOP 0
+
+#define RESOURCED_ATTRIBUTE_LARGEMEMORY                0x01
+#define RESOURCED_ATTRIBUTE_OOMTERMINATION     0X02
+#define RESOURCED_ATTRIBUTE_WEB_APP            0x04
+#define RESOURCED_ATTRIBUTE_DOWNLOAD_APP       0x08
+#define RESOURCED_ATTRIBUTE_SERVICE_APP                0x10
+
+int _signal_init(void);
+int _signal_send_watchdog(int pid, int signal_num);
+int _signal_send_proc_prelaunch(const char *appid, const char *pkgid,
+               int attribute, int category);
+int _signal_send_proc_suspend(int pid);
+int _signal_send_tep_mount(char *mnt_path[], const char *pkgid);
+int _signal_send_tep_unmount(const char *mnt_path);
+int _signal_get_proc_status(const int pid, int *status, int *focused);
+int _signal_subscribe_startup_finished(int (*callback)(uid_t uid, void *data),
+               void *user_data);
+int _signal_unsubscribe_startup_finished(void);
+int _signal_send_cpu_boost(int req);
+int _signal_send_display_lock_state(const char *state, const char *flag,
+               unsigned int timeout);
+int _signal_send_system_service(int pid);
+int _signal_send_display_unlock_state(const char *state, const char *flag);
+int _signal_add_initializer(int (*callback)(void *data), void *user_data);
diff --git a/inc/amd_socket.h b/inc/amd_socket.h
new file mode 100644 (file)
index 0000000..a064162
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define LAUNCHPAD_PROCESS_POOL_SOCK ".launchpad-process-pool-sock"
+
+#define PAD_CMD_LAUNCH 0
+#define PAD_CMD_VISIBILITY 10
+#define PAD_CMD_ADD_LOADER 11
+#define PAD_CMD_REMOVE_LOADER 12
+#define PAD_CMD_MAKE_DEFAULT_SLOTS 13
+#define PAD_CMD_DEMAND 14
+#define PAD_CMD_PING 15
+
+int _create_sock_activation(void);
+int _create_server_sock(void);
+int _send_cmd_to_launchpad(const char *pad_type, uid_t uid, int cmd,
+               bundle *kb);
+void _send_result_to_client(int fd, int res);
+void _send_result_to_client_v2(int fd, int res);
diff --git a/inc/amd_suspend.h b/inc/amd_suspend.h
new file mode 100644 (file)
index 0000000..db9fbde
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "amd_appinfo.h"
+
+#define SUSPEND_TYPE_EXCLUDE "exclude"
+#define SUSPEND_TYPE_INCLUDE "include"
+
+enum suspend_status_e {
+       SUSPEND_STATUS_EXCLUDE,
+       SUSPEND_STATUS_INCLUDE,
+};
+
+enum background_category_e {
+       BACKGROUND_CATEGORY_MEDIA = 0x01,
+       BACKGROUND_CATEGORY_DOWNLOAD = 0x02,
+       BACKGROUND_CATEGORY_BACKGROUND_NETWORK = 0x04,
+       BACKGROUND_CATEGORY_LOCATION = 0x08,
+       BACKGROUND_CATEGORY_SENSOR = 0x10,
+       BACKGROUND_CATEGORY_IOT_COMMUNICATION = 0x20,
+       BACKGROUND_CATEGORY_SYSTEM = 0x40
+};
+
+bool _suspend_is_allowed_background(const struct appinfo *ai);
+void _suspend_add_timer(int pid);
+void _suspend_remove_timer(int pid);
+int _suspend_add_proc(int pid);
+int _suspend_remove_proc(int pid);
+int _suspend_update_status(int pid, int status);
+void _suspend_init(void);
+void _suspend_fini(void);
diff --git a/inc/amd_util.h b/inc/amd_util.h
new file mode 100644 (file)
index 0000000..7a3a092
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <dlog.h>
+#include <glib.h>
+#include <tzplatform_config.h>
+
+#define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AMD"
+
+#define _E(fmt, arg...) LOGE(fmt, ##arg)
+#define _D(fmt, arg...) LOGD(fmt, ##arg)
+#define _W(fmt, arg...) LOGW(fmt, ##arg)
+#define _I(fmt, arg...) LOGI(fmt, ##arg)
+
+#define MAX_LOCAL_BUFSZ 128
+#define MAX_PID_STR_BUFSZ 20
+#define MAX_UID_STR_BUFSZ 20
+
+#define MAX_PACKAGE_STR_SIZE 512
+#define MAX_PACKAGE_APP_PATH_SIZE 512
+
+#define REGULAR_UID_MIN 5000
+
+#define GSLIST_FOREACH_SAFE(list, l, l_next)                   \
+       for (l = list, l_next = g_slist_next(l);                \
+                       l;                                      \
+                       l = l_next, l_next = g_slist_next(l))
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+int _util_save_log(const char *tag, const char *message);
+int _util_init(void);
+void _util_fini(void);
diff --git a/inc/app_signal.h b/inc/app_signal.h
new file mode 100644 (file)
index 0000000..d78089c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define AUL_DBUS_PATH                          "/aul/dbus_handler"
+#define AUL_DBUS_SIGNAL_INTERFACE              "org.tizen.aul.signal"
+#define AUL_DBUS_APPDEAD_SIGNAL                        "app_dead"
+#define AUL_DBUS_APPLAUNCH_SIGNAL              "app_launch"
+#define AUL_DBUS_HOMELAUNCH_SIGNAL             "home_launch"
+
+#define AUL_APP_STATUS_DBUS_PATH               "/Org/Tizen/Aul/AppStatus"
+#define AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE   "org.tizen.aul.AppStatus"
+#define STATUS_FOREGROUND                      "fg"
+#define STATUS_BACKGROUND                      "bg"
+#define AUL_APP_STATUS_DBUS_LAUNCH_REQUEST     "AppLaunch"
+#define AUL_APP_STATUS_DBUS_RESUME_REQUEST     "AppResume"
+#define AUL_APP_STATUS_DBUS_TERMINATE_REQUEST  "AppTerminate"
+#define AUL_APP_STATUS_DBUS_STATUS_CHANGE      "AppStatusChange"
+#define AUL_APP_STATUS_DBUS_GROUP              "AppGroup"
+#define AUL_APP_STATUS_DBUS_TERMINATED         "AppTerminated"
+
+#define SYSTEM_PATH_CORE                       "/Org/Tizen/System/DeviceD/Core"
+#define SYSTEM_INTERFACE_CORE                  "org.tizen.system.deviced.core"
+#define SYSTEM_SIGNAL_BOOTING_DONE             "BootingDone"
+
+#define SYSTEM_PATH_SYSNOTI                    "/Org/Tizen/System/DeviceD/SysNoti"
+#define SYSTEM_INTERFACE_SYSNOTI               "org.tizen.system.deviced.SysNoti"
+#define SYSTEM_SIGNAL_COOLDOWN_CHANGED         "CoolDownChanged"
+
+#define ROTATION_BUS_NAME                      "org.tizen.system.coord"
+#define ROTATION_OBJECT_PATH                   "/Org/Tizen/System/Coord/Rotation"
+#define ROTATION_INTERFACE_NAME                        "org.tizen.system.coord.rotation"
+#define ROTATION_METHOD_NAME                   "Degree"
+
+#define APPFW_SUSPEND_HINT_PATH                        "/Org/Tizen/Appfw/SuspendHint"
+#define APPFW_SUSPEND_HINT_INTERFACE           "org.tizen.appfw.SuspendHint"
+#define APPFW_SUSPEND_HINT_SIGNAL              "SuspendHint"
+
+#define RESOURCED_FREEZER_PATH                 "/Org/Tizen/Resourced/Freezer"
+#define RESOURCED_FREEZER_INTERFACE            "org.tizen.resourced.freezer"
+#define RESOURCED_FREEZER_SIGNAL               "FreezerState"
+
+#define RESOURCED_PROC_OBJECT                  "/Org/Tizen/ResourceD/Process"
+#define RESOURCED_PROC_INTERFACE               "org.tizen.resourced.process"
+#define RESOURCED_PROC_METHOD                  "ProcExclude"
+#define RESOURCED_PROC_PRELAUNCH_SIGNAL                "ProcPrelaunch"
+#define RESOURCED_PROC_WATCHDOG_SIGNAL         "ProcWatchdog"
+#define RESOURCED_PROC_GROUP_SIGNAL            "ProcGroup"
+#define RESOURCED_SYSTEM_SERVICE_SIGNAL                "SystemService"
+#define RESOURCED_ALLOWED_BG_ATTRIBUTE         0x100
+#define RESOURCED_BG_MANAGEMENT_ATTRIBUTE      0x200
+#define RESOURCED_API_VER_2_4_ATTRIBUTE                0x400
+
+#define PASS_BUS_NAME                          "org.tizen.system.pass"
+#define PASS_PATH_PMQOS                                "/Org/Tizen/System/Pass/Pmqos"
+#define PASS_INTERFACE_PMQOS                   "org.tizen.system.pass.pmqos"
+#define PASS_METHOD_APPLAUNCH                  "AppLaunch"
+
+#define SYSTEM_BUS_NAME                                "org.tizen.system.deviced"
+#define TEP_BUS_NAME                           SYSTEM_BUS_NAME
+#define TEP_OBJECT_PATH                                "/Org/Tizen/System/DeviceD/Tzip"
+#define TEP_INTERFACE_NAME                     "org.tizen.system.deviced.Tzip"
+#define TEP_MOUNT_METHOD                       "Mount"
+#define TEP_UNMOUNT_METHOD                     "Unmount"
+#define TEP_IS_MOUNTED_METHOD                  "IsMounted"
+
+#define WM_PROC_NAME                           "org.enlightenment.wm"
+#define WM_PROC_PATH                           "/org/enlightenment/wm"
+#define WM_PROC_INTERFACE                      "org.enlightenment.wm.proc"
+#define WM_PROC_METHOD                         "GetProcStatus"
+
+#define SD_BUS_NAME                            "org.freedesktop.systemd1"
+#define SD_OBJECT_PATH                         "/org/freedesktop/systemd1"
+#define SD_MANAGER_INTERFACE                   "org.freedesktop.systemd1.Manager"
+#define SD_STARTUP_FINISHED_SIGNAL             "StartupFinished"
+#define SD_USER_SESSION_STARTUP_FINISHED_SIGNAL        "UserSessionStartupFinished"
+#define SD_SUBSCRIBE_METHOD                    "Subscribe"
+#define SD_UNIT_OBJECT_PATH                    "/org/freedesktop/systemd1/unit/default_2etarget"
+#define SD_PROPERTIES_INTERFACE                        "org.freedesktop.DBus.Properties"
+#define SD_GET_METHOD                          "Get"
+
+#define SYSTEM_PATH_DISPLAY                    "/Org/Tizen/System/DeviceD/Display"
+#define SYSTEM_INTERFACE_DISPLAY               "org.tizen.system.deviced.display"
+#define SYSTEM_LOCK_STATE                      "lockstate"
+#define SYSTEM_UNLOCK_STATE                    "unlockstate"
+#define SYSTEM_LCD_OFF                         "lcdoff"
+#define SYSTEM_STAY_CUR_STATE                  "staycurstate"
+#define SYSTEM_SLEEP_MARGIN                    "sleepmargin"
diff --git a/inc/aul_svc_priv_key.h b/inc/aul_svc_priv_key.h
new file mode 100644 (file)
index 0000000..a01f33c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+/** AUL SVC internal private key */
+#define AUL_SVC_K_OPERATION    "__APP_SVC_OP_TYPE__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_URI          "__APP_SVC_URI__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_MIME         "__APP_SVC_MIME_TYPE__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_DATA         "__APP_SVC_DATA__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_PKG_NAME     "__APP_SVC_PKG_NAME__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_CATEGORY     "__APP_SVC_CATEGORY__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_RES_VAL      "__APP_SVC_K_RES_VAL__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_WIN_ID       "__APP_SVC_K_WIN_ID__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_LAUNCH_MODE   "__APP_SVC_LAUNCH_MODE__"
diff --git a/libamd.pc.in b/libamd.pc.in
new file mode 100644 (file)
index 0000000..3a297a3
--- /dev/null
@@ -0,0 +1,13 @@
+# Package Information for pkg-config
+
+prefix=/usr
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@
+
+Name: libamd
+Description: amd library for making plugins
+Version: @VERSION@
+Requires: bundle
+Libs: -L${libdir} -lamd
+Cflags: -I${includedir} -I${includedir}/amd
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
new file mode 100644 (file)
index 0000000..65c3b01
--- /dev/null
@@ -0,0 +1,14 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+ADD_SUBDIRECTORY(wayland-core)
+ADD_SUBDIRECTORY(cooldown)
+ADD_SUBDIRECTORY(splash-screen)
+ADD_SUBDIRECTORY(input)
+ADD_SUBDIRECTORY(widget)
+ADD_SUBDIRECTORY(launchpad)
+ADD_SUBDIRECTORY(share)
+ADD_SUBDIRECTORY(ui-core)
+ADD_SUBDIRECTORY(extractor)
+ADD_SUBDIRECTORY(cynara-core)
+ADD_SUBDIRECTORY(rua)
diff --git a/modules/cooldown/CMakeLists.txt b/modules/cooldown/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fcee38f
--- /dev/null
@@ -0,0 +1,42 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_COOLDOWN "amd-mod-cooldown")
+SET(AMD_MOD_COOLDOWN_DIR ${CMAKE_SOURCE_DIR}/modules/cooldown)
+PROJECT(${AMD_MOD_COOLDOWN} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_COOLDOWN_DIR}/src AMD_MOD_COOLDOWN_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_COOLDOWN_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       aul
+       )
+
+pkg_check_modules(amd_mod_cooldown_pkgs REQUIRED ${AMD_MOD_COOLDOWN_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_cooldown_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_COOLDOWN_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_COOLDOWN} ${AMD_MOD_COOLDOWN_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_COOLDOWN} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_COOLDOWN} ${amd_mod_cooldown_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_COOLDOWN} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/cooldown/inc/amd_cooldown.h b/modules/cooldown/inc/amd_cooldown.h
new file mode 100644 (file)
index 0000000..8ffc675
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_COOLDOWN"
+
+#define _E(fmt, arg...) LOGE(fmt, ##arg)
+#define _D(fmt, arg...) LOGD(fmt, ##arg)
+#define _W(fmt, arg...) LOGW(fmt, ##arg)
+#define _I(fmt, arg...) LOGI(fmt, ##arg)
+
+#define EXPORT __attribute__ ((visibility("default")))
+
diff --git a/modules/cooldown/src/amd_cooldown.c b/modules/cooldown/src/amd_cooldown.c
new file mode 100644 (file)
index 0000000..c776c83
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <aul.h>
+#include <amd.h>
+
+#include "amd_cooldown.h"
+
+#define APP_SUPPORT_MODE_VIP_APPLICATION 0x00000010
+#define COOLDOWN_STATUS_RELEASE "Release"
+#define COOLDOWN_STATUS_LIMITACTION "LimitAction"
+
+enum cooldown_status_val {
+       COOLDOWN_RELEASE,
+       COOLDOWN_WARNING,
+       COOLDOWN_LIMIT,
+};
+
+static int cooldown_status;
+
+static void __cooldown_limitaction(amd_app_status_h app_status, void *data)
+{
+       amd_appinfo_h ai;
+       const char *taskmanage;
+       const char *cooldown;
+       const char *appid;
+       int app_type;
+       uid_t uid;
+
+       if (app_status == NULL)
+               return;
+
+       app_type = amd_app_status_get_app_type(app_status);
+       if (app_type == AMD_AT_WIDGET_APP || app_type == AMD_AT_WATCH_APP)
+               return;
+
+       uid = amd_app_status_get_uid(app_status);
+       appid = amd_app_status_get_appid(app_status);
+       ai = amd_appinfo_find(uid, appid);
+       if (ai == NULL)
+               return;
+
+       cooldown = amd_appinfo_get_value(ai, AMD_AIT_COOLDOWN);
+       if (cooldown && strcmp(cooldown, "true") != 0) {
+               if (app_type == AMD_AT_UI_APP) {
+                       taskmanage = amd_appinfo_get_value(ai,
+                                       AMD_AIT_TASKMANAGE);
+                       if (taskmanage && strcmp(taskmanage, "true") != 0)
+                               return;
+               }
+
+               amd_app_status_terminate_apps(appid, uid);
+       }
+}
+
+static void __cooldown_release(void)
+{
+       amd_uid_state state;
+       uid_t *uids;
+       int r;
+       int i;
+
+       r = amd_login_monitor_get_uids(&uids);
+       if (r <= 0)
+               return;
+
+       for (i = 0; i < r; ++i) {
+               state = amd_login_monitor_get_uid_state(uids[i]);
+               if (state == AMD_UID_STATE_ONLINE ||
+                               state == AMD_UID_STATE_ACTIVE)
+                       amd_launch_start_onboot_apps(uids[i]);
+       }
+       free(uids);
+}
+
+static int __cooldown_signal_cb(const char *status, void *data)
+{
+       _D("status %s", status);
+       if (strcmp(status, COOLDOWN_STATUS_LIMITACTION) == 0) {
+               cooldown_status = COOLDOWN_LIMIT;
+               amd_app_status_foreach_running_info(__cooldown_limitaction,
+                               NULL);
+       } else if (strcmp(status, COOLDOWN_STATUS_RELEASE) == 0) {
+               cooldown_status = COOLDOWN_RELEASE;
+               __cooldown_release();
+       }
+
+       return 0;
+}
+
+static int __check_cooldown_mode(amd_appinfo_h ai)
+{
+       const char *taskmanage;
+       const char *cooldown;
+       const char *comptype;
+
+       if (cooldown_status != COOLDOWN_LIMIT)
+               return 0;
+
+       cooldown = amd_appinfo_get_value(ai, AMD_AIT_COOLDOWN);
+       if (cooldown && strcmp(cooldown, "true") == 0)
+               return 0;
+
+       comptype = amd_appinfo_get_value(ai, AMD_AIT_COMPTYPE);
+       if (comptype == NULL) {
+               _E("Failed to get comptype");
+               return -1;
+       }
+
+       if (strcmp(comptype, APP_TYPE_WIDGET) == 0 ||
+                       strcmp(comptype, APP_TYPE_WATCH) == 0)
+               return 0;
+
+       if (strcmp(comptype, APP_TYPE_UI) == 0) {
+               taskmanage = amd_appinfo_get_value(ai, AMD_AIT_TASKMANAGE);
+               if (taskmanage && strcmp(taskmanage, "false") == 0)
+                       return 0;
+       }
+
+       _W("Cannot launch this application in COOLDOWN mode");
+       return -1;
+}
+
+static int __on_check_mode(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_appinfo_h info = arg3;
+
+       return __check_cooldown_mode(info);
+}
+
+static int __on_check_status(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       if (cooldown_status == COOLDOWN_LIMIT)
+               return -1;
+
+       return 0;
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       int r;
+
+       _D("cooldown init");
+       r = aul_listen_cooldown_signal(__cooldown_signal_cb, NULL);
+       if (r < 0)
+               return -1;
+
+       amd_noti_listen("launch.prepare.start", __on_check_mode);
+       amd_noti_listen("signal.send_watchdog.start", __on_check_status);
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       _D("cooldown fini");
+       aul_listen_cooldown_signal(NULL, NULL);
+}
diff --git a/modules/cynara-core/CMakeLists.txt b/modules/cynara-core/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1b809cb
--- /dev/null
@@ -0,0 +1,45 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_CYNARA_CORE "amd-mod-cynara-core")
+SET(AMD_MOD_CYNARA_CORE_DIR ${CMAKE_SOURCE_DIR}/modules/cynara-core)
+PROJECT(${AMD_MOD_CYNARA_CORE} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_CYNARA_CORE_DIR}/src AMD_MOD_CYNARA_CORE_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_CYNARA_CORE_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       aul
+       cynara-client-async
+       cynara-creds-socket
+       cynara-session
+       )
+
+pkg_check_modules(amd_mod_cynara_core_pkgs REQUIRED ${AMD_MOD_CYNARA_CORE_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_cynara_core_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_CYNARA_CORE_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_CYNARA_CORE} ${AMD_MOD_CYNARA_CORE_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_CYNARA_CORE} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_CYNARA_CORE} ${amd_mod_cynara_core_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_CYNARA_CORE} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/cynara-core/inc/amd_cynara_core.h b/modules/cynara-core/inc/amd_cynara_core.h
new file mode 100644 (file)
index 0000000..14b2d0c
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_CYNARA_CORE"
+
+#define _E(fmt, arg...) LOGE(fmt, ##arg)
+#define _D(fmt, arg...) LOGD(fmt, ##arg)
+#define _W(fmt, arg...) LOGW(fmt, ##arg)
+#define _I(fmt, arg...) LOGI(fmt, ##arg)
+
+#undef EXPORT
+#define EXPORT __attribute__ ((visibility("default")))
+
diff --git a/modules/cynara-core/src/amd_cynara_core.c b/modules/cynara-core/src/amd_cynara_core.c
new file mode 100644 (file)
index 0000000..ee2a833
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <malloc.h>
+#include <stdlib.h>
+#include <cynara-client-async.h>
+#include <cynara-creds-socket.h>
+#include <cynara-session.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <glib.h>
+#include <glib-unix.h>
+#include <aul_sock.h>
+#include <aul_svc.h>
+#include <aul_svc_priv_key.h>
+#include <aul.h>
+#include <amd.h>
+
+#include "amd_cynara_core.h"
+
+#define MAX_LOCAL_BUFSZ 128
+
+static cynara_async *r_cynara;
+static int cynara_fd = -1;
+static guint cynara_fd_id;
+static GHashTable *__checker_table;
+static GList *__sub_checkers;
+
+struct caller_info {
+       GHashTable *id_table;
+
+       char *user;
+       char *client;
+       char *session;
+
+       amd_cynara_response_cb callback;
+       void *user_data;
+};
+
+typedef struct _cynara_sub_checker {
+       char *name;
+       amd_cynara_sub_checker_func checker;
+} cynara_sub_checker;
+
+static gboolean __cancel_func(gpointer key, gpointer value, gpointer user_data)
+{
+       int r;
+
+       r = cynara_async_cancel_request(r_cynara, GPOINTER_TO_UINT(key));
+       if (r != CYNARA_API_SUCCESS)
+               _E("cynara_async_cancel_request failed.");
+
+       return TRUE;
+}
+
+static void __destroy_caller_info(struct caller_info *info)
+{
+       if (info == NULL)
+               return;
+
+       if (info->client)
+               free(info->client);
+
+       if (info->session)
+               free(info->session);
+
+       if (info->user)
+               free(info->user);
+
+       if (info->id_table) {
+               g_hash_table_foreach_remove(info->id_table, __cancel_func, NULL);
+               g_hash_table_destroy(info->id_table);
+       }
+
+       free(info);
+}
+
+static int __get_caller_info_from_cynara(int sockfd, struct caller_info *info)
+{
+       pid_t pid;
+       int r;
+       char buf[MAX_LOCAL_BUFSZ];
+
+       if (info == NULL)
+               return -1;
+
+       r = cynara_creds_socket_get_pid(sockfd, &pid);
+       if (r != CYNARA_API_SUCCESS) {
+               cynara_strerror(r, buf, MAX_LOCAL_BUFSZ);
+               _E("cynara_creds_socket_get_pid failed: %s", buf);
+               return -1;
+       }
+
+       info->session = cynara_session_from_pid(pid);
+       if (info->session == NULL) {
+               _E("cynara_session_from_pid failed.");
+               return -1;
+       }
+
+       r = cynara_creds_socket_get_user(sockfd, USER_METHOD_DEFAULT,
+                       &(info->user));
+       if (r != CYNARA_API_SUCCESS) {
+               cynara_strerror(r, buf, MAX_LOCAL_BUFSZ);
+               _E("cynara_cred_socket_get_user failed.");
+               return -1;
+       }
+
+       r = cynara_creds_socket_get_client(sockfd, CLIENT_METHOD_DEFAULT,
+                       &(info->client));
+       if (r != CYNARA_API_SUCCESS) {
+               cynara_strerror(r, buf, MAX_LOCAL_BUFSZ);
+               _E("cynara_creds_socket_get_client failed.");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void __resp_cb(cynara_check_id id, cynara_async_call_cause cause,
+               int resp, void *data)
+{
+       enum amd_cynara_result res;
+       struct caller_info *info = (struct caller_info *)data;
+       char *privilege;
+
+       _D("check id %u, cause %d, resp %d", id, cause, resp);
+
+       privilege = g_hash_table_lookup(info->id_table,
+                       GUINT_TO_POINTER(id));
+       if (privilege == NULL) {
+               _W("Cynara: resp: %u not exist in id_table", id);
+               return;
+       }
+
+       g_hash_table_remove(info->id_table, GUINT_TO_POINTER(id));
+
+       switch (cause) {
+       case CYNARA_CALL_CAUSE_ANSWER:
+               if (resp == CYNARA_API_ACCESS_ALLOWED) {
+                       if (g_hash_table_size(info->id_table) > 0)
+                               return;
+                       res = AMD_CYNARA_RET_ALLOWED;
+               } else {
+                       _E("cynara denied (%s|%s|%s|%s)", privilege,
+                                       info->client, info->session, info->user);
+                       res = AMD_CYNARA_RET_DENIED;
+               }
+               break;
+       case CYNARA_CALL_CAUSE_CANCEL:
+               _D("Cynara: resp: resp %d canceled", id);
+               return;
+       case CYNARA_CALL_CAUSE_FINISH:
+       case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
+       default:
+               _E("Cynara: resp: not answer");
+               res = AMD_CYNARA_RET_ERROR;
+               break;
+       }
+
+       if (info->callback)
+               info->callback(res, info->user_data);
+
+       __destroy_caller_info(info);
+}
+
+static enum amd_cynara_result __check_server(struct caller_info *info,
+               const char *privilege)
+{
+       int r;
+       cynara_check_id id;
+
+       r = cynara_async_create_request(r_cynara, info->client, info->session,
+                       info->user, privilege,
+                       &id, __resp_cb, info);
+       if (r != CYNARA_API_SUCCESS) {
+               _E("cynara_async_create_request error : %d", r);
+               return AMD_CYNARA_RET_ERROR;
+       }
+
+       g_hash_table_insert(info->id_table, GUINT_TO_POINTER(id),
+                       strdup(privilege));
+
+       return AMD_CYNARA_RET_UNKNOWN;
+}
+
+static enum amd_cynara_result __check_cache(struct caller_info *info,
+               const char *privilege)
+{
+       int ret;
+
+       ret = cynara_async_check_cache(r_cynara, info->client, info->session,
+                       info->user, privilege);
+       switch (ret) {
+       case CYNARA_API_ACCESS_ALLOWED:
+               ret = AMD_CYNARA_RET_ALLOWED;
+               break;
+       case CYNARA_API_ACCESS_DENIED:
+               ret = AMD_CYNARA_RET_DENIED;
+               break;
+       case CYNARA_API_CACHE_MISS:
+               ret = AMD_CYNARA_RET_UNKNOWN;
+               break;
+       default:
+               _E("cynara cache error %d (%s|%s|%s)", ret,
+                               info->client, info->session, info->user);
+               ret = AMD_CYNARA_RET_UNKNOWN;
+               break;
+       }
+
+       return ret;
+}
+
+static int __cynara_simple_checker(amd_cynara_caller_info_h info, amd_request_h req, void *data)
+{
+       int ret;
+       const char *privilege = data;
+
+       ret = __check_cache(info, privilege);
+       if (ret != AMD_CYNARA_RET_UNKNOWN) {
+               if (ret == AMD_CYNARA_RET_DENIED) {
+                       _E("cynara denied (%s|%s|%s|%s)", privilege,
+                                       info->client, info->session, info->user);
+               }
+               return ret;
+       }
+
+       return __check_server(info, privilege);
+}
+
+static int __check_privilege_by_checker(amd_request_h req, amd_cynara_caller_info_h info)
+{
+       int ret;
+       amd_cynara_checker *checker;
+
+       checker = g_hash_table_lookup(__checker_table,
+                       GINT_TO_POINTER(amd_request_get_cmd(req)));
+       if (checker && checker->checker) {
+               ret = checker->checker(info, req, checker->data);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct caller_info *__create_caller_info(amd_request_h req,
+               amd_cynara_response_cb callback)
+{
+       int r;
+       struct caller_info *info;
+
+       info = calloc(1, sizeof(*info));
+       if (info == NULL) {
+               _E("insufficient memory");
+               return NULL;
+       }
+
+       r = __get_caller_info_from_cynara(amd_request_get_fd(req), info);
+       if (r < 0) {
+               _E("Failed to get caller info");
+               __destroy_caller_info(info);
+               return NULL;
+       }
+
+       info->callback = callback;
+       info->user_data = req;
+
+       info->id_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                       NULL, free);
+
+       return info;
+}
+
+static int __cynara_check_privilege(amd_request_h req, amd_cynara_response_cb callback)
+{
+       int r;
+       struct caller_info *info;
+
+       info = __create_caller_info(req, callback);
+       if (info == NULL)
+               return -1;
+
+       r = __check_privilege_by_checker(req, info);
+
+       if (r != AMD_CYNARA_RET_UNKNOWN)
+               __destroy_caller_info(info);
+
+       return r;
+}
+
+static gboolean __proc_cb(gint fd, GIOCondition cond, gpointer data)
+{
+       int ret;
+
+       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+               cynara_fd_id = 0;
+               return G_SOURCE_REMOVE;
+       }
+
+       ret = cynara_async_process(r_cynara);
+       if (ret != CYNARA_API_SUCCESS)
+               _E("process error %d", ret);
+
+       return G_SOURCE_CONTINUE;
+}
+
+static void __status_cb(int old_fd, int new_fd, cynara_async_status status,
+               void *data)
+{
+       if (old_fd != -1) {
+               if (cynara_fd_id) {
+                       g_source_remove(cynara_fd_id);
+                       cynara_fd_id = 0;
+               }
+               cynara_fd = -1;
+       }
+
+       if (new_fd != -1) {
+               GIOCondition cond;
+
+               cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+               if (status == CYNARA_STATUS_FOR_RW)
+                       cond |= G_IO_OUT;
+
+               cynara_fd_id = g_unix_fd_add(new_fd, cond, __proc_cb, data);
+               cynara_fd = new_fd;
+       }
+}
+
+static int __cynara_register_checkers(const amd_cynara_checker *checkers, int cnt)
+{
+       int i;
+       amd_cynara_checker *c;
+
+       if (cnt <= 0 || !__checker_table || !checkers)
+               return -1;
+
+       for (i = 0; i < cnt; i++) {
+               c = g_hash_table_lookup(__checker_table,
+                       GINT_TO_POINTER(checkers[i].cmd));
+               if (c) {
+                       if (checkers[i].priority <= c->priority)
+                               continue;
+
+                       g_hash_table_remove(__checker_table,
+                               GINT_TO_POINTER(checkers[i].cmd));
+               }
+
+               g_hash_table_insert(__checker_table,
+                               GINT_TO_POINTER(checkers[i].cmd),
+                               (gpointer)(&checkers[i]));
+       }
+
+       return 0;
+}
+
+static const char *__cynara_caller_info_get_client(amd_cynara_caller_info_h info)
+{
+       if (!info)
+               return NULL;
+
+       return info->client;
+}
+
+static int __cynara_sub_checker_add(const char *name, amd_cynara_sub_checker_func func)
+{
+       cynara_sub_checker *c;
+
+       if (!name || !func)
+               return -1;
+
+       c = calloc(1, sizeof(cynara_sub_checker));
+       if (!c)
+               return -1;
+
+       c->name = strdup(name);
+       c->checker = func;
+
+       if (!(c->name)) {
+               free(c);
+               return -1;
+       }
+
+       __sub_checkers = g_list_append(__sub_checkers, c);
+
+       return 0;
+}
+
+static int __cynara_sub_checker_check(const char *name, amd_cynara_caller_info_h info, amd_request_h req)
+{
+       GList *i = __sub_checkers;
+       cynara_sub_checker *c;
+       int ret;
+
+       if (!name || !info || !req)
+               return AMD_CYNARA_RET_ERROR;
+
+       while (i) {
+               c = i->data;
+               if (!strcmp(name, c->name)) {
+                       ret = c->checker(info, req);
+                       if (ret != AMD_CYNARA_RET_CONTINUE)
+                               return ret;
+               }
+
+               i = g_list_next(i);
+       }
+
+       return AMD_CYNARA_RET_CONTINUE;
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       int ret;
+
+       _D("Cynara-core init");
+       ret = cynara_async_initialize(&r_cynara, NULL, __status_cb, NULL);
+       if (ret != CYNARA_API_SUCCESS) {
+               _E("cynara initialize failed. %d", ret);
+               return ret;
+       }
+
+       __checker_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                       NULL, NULL);
+
+       amd_cynara_ops ops = {
+               .register_checkers = __cynara_register_checkers,
+               .sub_checker_add = __cynara_sub_checker_add,
+               .sub_checker_check = __cynara_sub_checker_check,
+               .check_async = __cynara_check_privilege,
+               .check = __cynara_simple_checker
+       };
+
+       amd_cynara_caller_info_ops ci_ops = {
+               .get_client = __cynara_caller_info_get_client
+       };
+
+       return amd_cynara_register_ops(ops, ci_ops);
+}
+
+static void __free_sub_checker(gpointer data)
+{
+       cynara_sub_checker *c = data;
+
+       free(c->name);
+       free(c);
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       _D("Cynara-core fini");
+       if (r_cynara == NULL)
+               return;
+
+       if (cynara_fd_id) {
+               g_source_remove(cynara_fd_id);
+               cynara_fd_id = 0;
+       }
+
+       cynara_async_finish(r_cynara);
+       r_cynara = NULL;
+       cynara_fd = -1;
+
+       if (__checker_table) {
+               g_hash_table_destroy(__checker_table);
+               __checker_table = NULL;
+       }
+
+       if (__sub_checkers) {
+               g_list_free_full(__sub_checkers, __free_sub_checker);
+               __sub_checkers = NULL;
+       }
+}
+
+
diff --git a/modules/extractor/CMakeLists.txt b/modules/extractor/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b3678ca
--- /dev/null
@@ -0,0 +1,43 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_EXTRACTOR "amd-mod-extractor")
+SET(AMD_MOD_EXTRACTOR_DIR ${CMAKE_SOURCE_DIR}/modules/extractor)
+PROJECT(${AMD_MOD_EXTRACTOR} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_EXTRACTOR_DIR}/src AMD_MOD_EXTRACTOR_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_EXTRACTOR_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       aul
+       libtzplatform-config
+       )
+
+pkg_check_modules(amd_mod_extractor_pkgs REQUIRED ${AMD_MOD_EXTRACTOR_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_extractor_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_EXTRACTOR_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_EXTRACTOR} ${AMD_MOD_EXTRACTOR_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_EXTRACTOR} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_EXTRACTOR} ${amd_mod_extractor_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_EXTRACTOR} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/extractor/inc/amd_extractor.h b/modules/extractor/inc/amd_extractor.h
new file mode 100644 (file)
index 0000000..cb95800
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_EXTRACTOR"
+
+#define _E(fmt, arg...) LOGE(fmt, ##arg)
+#define _D(fmt, arg...) LOGD(fmt, ##arg)
+#define _W(fmt, arg...) LOGW(fmt, ##arg)
+#define _I(fmt, arg...) LOGI(fmt, ##arg)
+
+#define EXPORT __attribute__ ((visibility("default")))
+
diff --git a/modules/extractor/src/amd_extractor.c b/modules/extractor/src/amd_extractor.c
new file mode 100644 (file)
index 0000000..0faa02f
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <aul.h>
+#include <bundle_internal.h>
+#include <tzplatform_config.h>
+
+#include "amd.h"
+#include "amd_extractor.h"
+
+#define PATH_APP_ROOT tzplatform_getenv(TZ_USER_APP)
+#define PATH_GLOBAL_APP_RO_ROOT tzplatform_getenv(TZ_SYS_RO_APP)
+#define PATH_GLOBAL_APP_RW_ROOT tzplatform_getenv(TZ_SYS_RW_APP)
+
+typedef char **(_extractor_mountable)(const amd_appinfo_h ai);
+
+static GHashTable *mount_point_hash;
+
+static const char *__get_app_root_path(const amd_appinfo_h ai)
+{
+       const char *path_app_root;
+       const char *global;
+       const char *preload;
+
+       preload = amd_appinfo_get_value(ai, AMD_AIT_PRELOAD);
+       global = amd_appinfo_get_value(ai, AMD_AIT_GLOBAL);
+       if (global && strcmp(global, "true") == 0) {
+               if (preload && strcmp(preload, "true") == 0)
+                       path_app_root = PATH_GLOBAL_APP_RO_ROOT;
+               else
+                       path_app_root = PATH_GLOBAL_APP_RW_ROOT;
+       } else {
+               path_app_root = PATH_APP_ROOT;
+       }
+
+       return path_app_root;
+}
+
+static char **__extractor_mountable_get_tep_paths(const amd_appinfo_h ai)
+{
+       char tep_path[PATH_MAX];
+       char **mnt_path;
+       const char *pkgid;
+       const char *tep_name;
+
+       if (ai == NULL)
+               return NULL;
+
+       pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+       if (pkgid == NULL)
+               return NULL;
+
+       tep_name = amd_appinfo_get_value(ai, AMD_AIT_TEP);
+       if (tep_name == NULL)
+               return NULL;
+
+       mnt_path = (char **)malloc(sizeof(char *) * 2);
+       if (mnt_path == NULL) {
+               _E("out of memory");
+               return NULL;
+       }
+
+       mnt_path[1] = strdup(tep_name);
+       if (mnt_path[1] == NULL) {
+               _E("Out of memory");
+               free(mnt_path);
+               return NULL;
+       }
+       snprintf(tep_path, PATH_MAX, "%s/%s/tep/mount",
+                       __get_app_root_path(ai), pkgid);
+       mnt_path[0] = strdup(tep_path);
+       if (mnt_path[0] == NULL) {
+               _E("Out of memory");
+               free(mnt_path[1]);
+               free(mnt_path);
+               return NULL;
+       }
+
+       return mnt_path;
+}
+
+static char **__extractor_mountable_get_tpk_paths(const amd_appinfo_h ai)
+{
+       char mount_point[PATH_MAX];
+       char **mnt_path;
+       const char *pkgid;
+       const char *tpk;
+
+       if (ai == NULL)
+               return NULL;
+
+       pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+       if (pkgid == NULL)
+               return NULL;
+
+       tpk = amd_appinfo_get_value(ai, AMD_AIT_MOUNTABLE_PKG);
+       if (tpk == NULL)
+               return NULL;
+
+       mnt_path = (char **)malloc(sizeof(char *) * 2);
+       if (mnt_path == NULL) {
+               _E("out of memory");
+               return NULL;
+       }
+
+       mnt_path[1] = strdup(tpk);
+       if (mnt_path[1] == NULL) {
+               _E("Out of memory");
+               free(mnt_path);
+               return NULL;
+       }
+       snprintf(mount_point, PATH_MAX, "%s/%s/.pkg",
+                               __get_app_root_path(ai), pkgid);
+       mnt_path[0] = strdup(mount_point);
+       if (mnt_path[0] == NULL) {
+               free(mnt_path[1]);
+               free(mnt_path);
+               return NULL;
+       }
+
+       return mnt_path;
+}
+
+static void __free_path(char **path, int cnt)
+{
+       int i;
+
+       if (path == NULL)
+               return;
+
+       for (i = 0; i < cnt; i++) {
+               if (path[i])
+                       free(path[i]);
+       }
+       free(path);
+}
+
+static void __free_set(gpointer data)
+{
+       g_hash_table_destroy((GHashTable *)data);
+}
+
+static void __prepare_map(void)
+{
+       if (mount_point_hash == NULL) {
+               mount_point_hash = g_hash_table_new_full(g_str_hash,
+                               g_str_equal, free, __free_set);
+       }
+}
+
+static void __put_mount_path(const amd_appinfo_h ai, const char *str)
+{
+       const char *appid;
+       GHashTable *set;
+
+       __prepare_map();
+       set = g_hash_table_lookup(mount_point_hash, str);
+       if (set == NULL) {
+               set = g_hash_table_new_full(g_str_hash, g_str_equal,
+                               free, NULL);
+               if (set == NULL)
+                       return;
+               g_hash_table_insert(mount_point_hash, strdup(str), set);
+       }
+
+       appid = amd_appinfo_get_value(ai, AMD_AIT_NAME);
+       g_hash_table_insert(set, strdup(appid), NULL);
+}
+
+static bool __is_unmountable(const char *appid, const char *key)
+{
+       GHashTable *set;
+
+       if (amd_app_status_get_process_cnt(appid) > 1)
+               return false;
+
+       __prepare_map();
+       set = g_hash_table_lookup(mount_point_hash, key);
+
+       if (set == NULL)
+               return false;
+
+       g_hash_table_remove(set, appid);
+       if (g_hash_table_size(set) > 0)
+               return false;
+
+       return true;
+}
+
+static void __extractor_mount(const amd_appinfo_h ai, bundle *kb,
+               _extractor_mountable mountable)
+{
+       int ret;
+       const char **array = NULL;
+       int len = 0;
+       const char *default_array[1] = { NULL };
+       char **new_array = NULL;
+       int i;
+       bool dup = false;
+       const char *pkgid = NULL;
+       char **mnt_path;
+
+       mnt_path = mountable(ai);
+       if (mnt_path == NULL)
+               return;
+
+       if (!mnt_path[0] || !mnt_path[1]) {
+               __free_path(mnt_path, 2);
+               return;
+       }
+
+       array = bundle_get_str_array(kb, AUL_TEP_PATH, &len);
+       if (array == NULL) {
+               default_array[0] = mnt_path[0];
+               bundle_add_str_array(kb, AUL_TEP_PATH,
+                                    default_array, 1);
+       } else {
+               for (i = 0; i < len; i++) {
+                       if (strcmp(mnt_path[0], array[i]) == 0) {
+                               dup = true;
+                               break;
+                       }
+               }
+
+               if (!dup) {
+                       new_array = calloc(len + 1, sizeof(char *));
+                       if (new_array == NULL) {
+                               _E("out of memory");
+                               __free_path(mnt_path, 2);
+                               return;
+                       }
+
+                       for (i = 0; i < len; i++) {
+                               new_array[i] = strdup(array[i]);
+                               if (new_array[i] == NULL) {
+                                       _E("Out of memory");
+                                       __free_path(new_array, i);
+                                       return;
+                               }
+                       }
+                       new_array[len] = strdup(mnt_path[0]);
+                       if (new_array[len] == NULL) {
+                               _E("Out of memory");
+                               __free_path(new_array, len);
+                               return;
+                       }
+                       bundle_del(kb, AUL_TEP_PATH);
+                       bundle_add_str_array(kb, AUL_TEP_PATH,
+                                       (const char **)new_array, len + 1);
+                       __free_path(new_array, len + 1);
+               }
+       }
+
+       __put_mount_path(ai, mnt_path[0]);
+       ret = aul_is_tep_mount_dbus_done(mnt_path[0]);
+       if (ret != 1) {
+               pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+               ret = amd_signal_send_tep_mount(mnt_path, pkgid);
+               if (ret < 0) {
+                       _E("dbus error %d", ret);
+               } else {
+                       _D("Mount request was sent %s %s",
+                                       mnt_path[0], mnt_path[1]);
+               }
+       }
+
+       __free_path(mnt_path, 2);
+}
+
+static void __extractor_unmount(int pid, _extractor_mountable mountable)
+{
+       const char *appid;
+       amd_appinfo_h ai;
+       int ret;
+       char **mnt_path;
+       amd_app_status_h app_status;
+       uid_t uid;
+
+       app_status = amd_app_status_find_by_pid(pid);
+       if (app_status == NULL)
+               return;
+
+       uid = amd_app_status_get_uid(app_status);
+       appid = amd_app_status_get_appid(app_status);
+       if (appid == NULL)
+               return;
+
+       ai = amd_appinfo_find(uid, appid);
+       if (ai == NULL)
+               return;
+
+       mnt_path = mountable(ai);
+       if (mnt_path == NULL)
+               return;
+
+       if (!__is_unmountable(appid, mnt_path[0]))
+               return;
+
+       g_hash_table_remove(mount_point_hash, mnt_path[0]);
+       ret = amd_signal_send_tep_unmount(mnt_path[0]);
+       if (ret < 0)
+               _E("Failed to send unmount: %s", mnt_path[0]);
+       else
+               _D("Unmount request was sent %s", mnt_path[0]);
+
+       __free_path(mnt_path, 2);
+}
+
+static int __on_app_status_cleanup(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_app_status_h app_status = arg3;
+       int pid;
+
+       pid = amd_app_status_get_pid(app_status);
+       __extractor_unmount(pid, __extractor_mountable_get_tep_paths);
+       __extractor_unmount(pid, __extractor_mountable_get_tpk_paths);
+
+       return 0;
+}
+
+static int __on_launch_prepared(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       const amd_appinfo_h info = arg3;
+
+       __extractor_mount(info, data, __extractor_mountable_get_tep_paths);
+       __extractor_mount(info, data, __extractor_mountable_get_tpk_paths);
+
+       return 0;
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       _D("extractor init");
+
+       amd_noti_listen("app_status.cleanup", __on_app_status_cleanup);
+       amd_noti_listen("launch.prepare.end", __on_launch_prepared);
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       _D("extractor fini");
+}
+
diff --git a/modules/input/CMakeLists.txt b/modules/input/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d8cc086
--- /dev/null
@@ -0,0 +1,47 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_INPUT "amd-mod-input")
+SET(AMD_MOD_INPUT_DIR ${CMAKE_SOURCE_DIR}/modules/input)
+PROJECT(${AMD_MOD_INPUT} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_INPUT_DIR}/src AMD_MOD_INPUT_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_INPUT_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       aul
+       wayland-client
+       wayland-tbm-client
+       tizen-extension-client
+       xkbcommon
+       capi-system-info
+       )
+
+pkg_check_modules(amd_mod_input_pkgs REQUIRED ${AMD_MOD_INPUT_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_input_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_INPUT_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_INPUT} ${AMD_MOD_INPUT_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_INPUT} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_INPUT} ${amd_mod_input_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_INPUT} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/input/inc/amd_input.h b/modules/input/inc/amd_input.h
new file mode 100644 (file)
index 0000000..1561bef
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_INPUT"
+
+#undef EXPORT
+#define EXPORT __attribute__ ((visibility("default")))
diff --git a/modules/input/src/amd_input.c b/modules/input/src/amd_input.c
new file mode 100644 (file)
index 0000000..1b1c1bf
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdbool.h>
+#include <malloc.h>
+#include <sys/mman.h>
+
+#include <glib.h>
+#include <wayland-client.h>
+#include <tizen-extension-client-protocol.h>
+#include <xkbcommon/xkbcommon.h>
+#include <aul.h>
+
+#include "amd.h"
+#include "amd_input.h"
+
+#define TIMEOUT_VAL 1000
+
+static bool locked;
+static bool init_done;
+static bool noti_registered;
+static guint timer;
+static struct tizen_keyrouter *keyrouter;
+static struct tizen_input_device_manager *input_devmgr;
+static struct wl_display *display;
+static struct wl_seat *seat;
+static guint sid;
+
+struct xkb_context *g_ctx;
+struct xkb_keymap *g_keymap;
+struct wl_keyboard *keyboard;
+
+typedef struct _keycode_map {
+       xkb_keysym_t keysym;
+       xkb_keycode_t *keycodes;
+       int nkeycodes;
+} keycode_map;
+
+static int __input_lock(void);
+static int __input_unlock(void);
+
+// This will be removed once rpms are devided [
+#include <stdlib.h>
+#include <system_info.h>
+
+typedef enum {
+       TIZEN_PROFILE_UNKNOWN = 0,
+       TIZEN_PROFILE_MOBILE = 0x1,
+       TIZEN_PROFILE_WEARABLE = 0x2,
+       TIZEN_PROFILE_TV = 0x4,
+       TIZEN_PROFILE_IVI = 0x8,
+       TIZEN_PROFILE_COMMON = 0x10,
+} tizen_profile_t;
+
+#define TIZEN_FEATURE_BLOCK_INPUT \
+       (!(__get_tizen_profile() & (TIZEN_PROFILE_TV | TIZEN_PROFILE_IVI)))
+
+static tizen_profile_t __get_tizen_profile(void)
+{
+       static tizen_profile_t profile = TIZEN_PROFILE_UNKNOWN;
+       char *profile_name = NULL;
+
+       if (__builtin_expect(profile != TIZEN_PROFILE_UNKNOWN, 1))
+               return profile;
+
+       system_info_get_platform_string("http://tizen.org/feature/profile",
+                       &profile_name);
+       if (profile_name == NULL)
+               return profile;
+
+       switch (*profile_name) {
+       case 'm':
+       case 'M':
+               profile = TIZEN_PROFILE_MOBILE;
+               break;
+       case 'w':
+       case 'W':
+               profile = TIZEN_PROFILE_WEARABLE;
+               break;
+       case 't':
+       case 'T':
+               profile = TIZEN_PROFILE_TV;
+               break;
+       case 'i':
+       case 'I':
+               profile = TIZEN_PROFILE_IVI;
+               break;
+       default: /* common or unknown ==> ALL ARE COMMON. */
+               profile = TIZEN_PROFILE_COMMON;
+               break;
+       }
+       free(profile_name);
+
+       return profile;
+}
+// ]
+
+static void __keyboard_keymap(void *data, struct wl_keyboard *keyboard,
+               uint32_t format, int fd, uint32_t size)
+{
+       char *map = NULL;
+
+       LOGD("format=%d, fd=%d, size=%d", format, fd, size);
+       if (!g_ctx) {
+               LOGE("This client failed to make xkb context");
+               close(fd);
+               return;
+       }
+
+       if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
+               LOGE("Invaild format: %d", format);
+               close(fd);
+               return;
+       }
+
+       map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+       if (map == MAP_FAILED) {
+               LOGE("Failed to mmap from fd(%d) size(%d)", fd, size);
+               close(fd);
+               return;
+       }
+
+       g_keymap = xkb_map_new_from_string(g_ctx, map,
+                       XKB_KEYMAP_FORMAT_TEXT_V1, 0);
+       munmap(map, size);
+       if (!g_keymap)
+               LOGE("Failed to get keymap from fd(%d)", fd);
+       close(fd);
+}
+
+static void __keyboard_enter(void *data, struct wl_keyboard *keyboard,
+               uint32_t serial, struct wl_surface *surface,
+               struct wl_array *keys)
+{
+       LOGD("serial=%d", serial);
+}
+
+static void __keyboard_leave(void *data, struct wl_keyboard *keyboard,
+               uint32_t serial, struct wl_surface *surface)
+{
+       LOGD("serial=%d", serial);
+}
+
+static void __keyboard_key(void *data, struct wl_keyboard *keyboard,
+               uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w)
+{
+       LOGD("serial=%d, time=%d, key=%d, state_w=%d",
+                       serial, time, key, state_w);
+}
+
+static void __keyboard_modifiers(void *data, struct wl_keyboard *keyboard,
+               uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
+               uint32_t mods_locked, uint32_t group)
+{
+       LOGD("serial=%d, mods_depressed=%d, mods_latched=%d mods_locked=%d, " \
+                       "group=%d", serial, mods_depressed, mods_latched,
+                       mods_locked, group);
+}
+
+static const struct wl_keyboard_listener keyboard_listener = {
+       .keymap = __keyboard_keymap,
+       .enter = __keyboard_enter,
+       .leave = __keyboard_leave,
+       .key = __keyboard_key,
+       .modifiers = __keyboard_modifiers
+};
+
+static gboolean __timeout_handler(void *data)
+{
+       timer = 0;
+       __input_unlock();
+       return FALSE;
+}
+
+static void __find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key,
+               void *data)
+{
+       keycode_map *found_keycodes = (keycode_map *)data;
+       xkb_keysym_t keysym = found_keycodes->keysym;
+       int nsyms = 0;
+       const xkb_keysym_t *syms_out = NULL;
+       xkb_keycode_t *temp_keycodes;
+
+       nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out);
+       if (nsyms && syms_out && *syms_out == keysym) {
+               found_keycodes->nkeycodes++;
+               temp_keycodes = realloc(found_keycodes->keycodes,
+                               sizeof(int) * found_keycodes->nkeycodes);
+               if (temp_keycodes == NULL) {
+                       LOGE("Out of memory");
+                       found_keycodes->nkeycodes--;
+                       return;
+               }
+               found_keycodes->keycodes = temp_keycodes;
+               found_keycodes->keycodes[found_keycodes->nkeycodes - 1] = key;
+       }
+}
+
+static int __xkb_keycode_from_keysym(struct xkb_keymap *keymap,
+               xkb_keysym_t keysym, xkb_keycode_t **keycodes)
+{
+       keycode_map found_keycodes = {0,};
+
+       found_keycodes.keysym = keysym;
+       xkb_keymap_key_for_each(g_keymap, __find_keycode, &found_keycodes);
+       *keycodes = found_keycodes.keycodes;
+
+       return found_keycodes.nkeycodes;
+}
+
+static void __keygrab_request(struct tizen_keyrouter *tizen_keyrouter,
+               struct wl_surface *surface, uint32_t key, uint32_t mode)
+{
+       tizen_keyrouter_set_keygrab(tizen_keyrouter, surface, key, mode);
+       LOGD("request set_keygrab (key:%d, mode:%d)!", key, mode);
+}
+
+static void __keyungrab_request(struct tizen_keyrouter *tizen_keyrouter,
+               struct wl_surface *surface, uint32_t key)
+{
+       tizen_keyrouter_unset_keygrab(tizen_keyrouter, surface, key);
+       LOGD("request unset_keygrab (key:%d)!", key);
+}
+
+static void __do_keygrab(const char *keyname, uint32_t mode)
+{
+       xkb_keysym_t keysym = 0x0;
+       int nkeycodes = 0;
+       xkb_keycode_t *keycodes = NULL;
+       int i;
+
+       keysym = xkb_keysym_from_name(keyname, XKB_KEYSYM_NO_FLAGS);
+       nkeycodes = __xkb_keycode_from_keysym(g_keymap, keysym, &keycodes);
+
+       for (i = 0; i < nkeycodes; i++) {
+               LOGD("%s's keycode is %d (nkeycode: %d)",
+                               keyname, keycodes[i], nkeycodes);
+               __keygrab_request(keyrouter, NULL, keycodes[i], mode);
+       }
+       free(keycodes);
+       keycodes = NULL;
+}
+
+static void __do_keyungrab(const char *keyname)
+{
+       xkb_keysym_t keysym = 0x0;
+       int nkeycodes = 0;
+       xkb_keycode_t *keycodes = NULL;
+       int i;
+
+       keysym = xkb_keysym_from_name(keyname, XKB_KEYSYM_NO_FLAGS);
+       nkeycodes = __xkb_keycode_from_keysym(g_keymap, keysym, &keycodes);
+
+       for (i = 0; i < nkeycodes; i++) {
+               LOGD("%s's keycode is %d (nkeycode: %d)\n",
+                               keyname, keycodes[i], nkeycodes);
+               __keyungrab_request(keyrouter, NULL, keycodes[i]);
+       }
+       free(keycodes);
+       keycodes = NULL;
+}
+
+static int __xkb_init(void)
+{
+       if (!g_ctx) {
+               g_ctx = xkb_context_new(0);
+               if (!g_ctx) {
+                       LOGE("Failed to get xkb_context");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static void __xkb_fini(void)
+{
+       if (g_ctx) {
+               xkb_context_unref(g_ctx);
+               g_ctx = NULL;
+       }
+}
+
+static void __input_device_info(void *data,
+               struct tizen_input_device *tizen_input_device,
+               const char *name, uint32_t class, uint32_t subclass,
+               struct wl_array *axes)
+{
+       LOGD("device info - name: %s, class: %d, subclass: %d",
+                       name, class, subclass);
+}
+
+static void __input_device_event_device(void *data,
+               struct tizen_input_device *tizen_input_device,
+               unsigned int serial, const char *name, uint32_t time)
+{
+       LOGD("event device - name: %s, time: %d", name, time);
+}
+
+static void __input_device_axis(void *data,
+               struct tizen_input_device *tizen_input_device,
+               uint32_t axis_type, wl_fixed_t value)
+{
+       LOGD("axis - axis_type: %d, value: %lf",
+                       axis_type, wl_fixed_to_double(value));
+}
+
+static const struct tizen_input_device_listener input_device_listener = {
+       __input_device_info,
+       __input_device_event_device,
+       __input_device_axis,
+};
+
+static void __cb_device_add(void *data,
+               struct tizen_input_device_manager *tizen_input_device_manager,
+               uint32_t serial, const char *name,
+               struct tizen_input_device *device, struct wl_seat *seat)
+{
+       LOGD("%s device is added!", name);
+       tizen_input_device_add_listener(device, &input_device_listener, NULL);
+}
+
+static void __cb_device_remove(void *data,
+               struct tizen_input_device_manager *tizen_input_device_manager,
+               uint32_t serial, const char *name,
+               struct tizen_input_device *device, struct wl_seat *seat)
+{
+       LOGD("%s device is removed!", name);
+       tizen_input_device_destroy(device);
+}
+
+static void __cb_error(void *data,
+               struct tizen_input_device_manager *tizen_input_device_manager,
+               uint32_t errorcode)
+{
+       LOGE("error: %d", errorcode);
+}
+
+static void __cb_block_expired(void *data,
+               struct tizen_input_device_manager *tizen_input_device_manager)
+{
+       LOGD("block expired");
+}
+
+static struct tizen_input_device_manager_listener input_devmgr_listener = {
+       __cb_device_add,
+       __cb_device_remove,
+       __cb_error,
+       __cb_block_expired
+};
+
+static int __on_lock(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       amd_app_status_h app_status = arg3;
+       int status;
+
+       if (TIZEN_FEATURE_BLOCK_INPUT) {
+               status = amd_app_status_get_status(app_status);
+               if (status != STATUS_VISIBLE && !arg1)
+                       __input_lock();
+       }
+
+       return 0;
+}
+
+static int __on_unlock(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       if (TIZEN_FEATURE_BLOCK_INPUT)
+               __input_unlock();
+
+       return 0;
+}
+
+static int __on_registry_handler(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       uint32_t id = (uint32_t)arg1;
+       struct wl_registry *registry = (struct wl_registry *)arg3;
+
+       if (!strcmp(msg, "wayland.listener.tizen_input_device_manager")) {
+               if (!input_devmgr) {
+                       input_devmgr = wl_registry_bind(registry, id,
+                                    &tizen_input_device_manager_interface,
+                                    1);
+                       LOGD("input_devmgr(%p)", input_devmgr);
+               }
+       } else if (!strcmp(msg, "wayland.listener.tizen_keyrouter")) {
+               if (!keyrouter) {
+                       keyrouter = wl_registry_bind(registry, id,
+                                       &tizen_keyrouter_interface, 1);
+                       LOGD("keyrouter(%p)", keyrouter);
+               }
+       } else if (!strcmp(msg, "wayland.listener.wl_seat")) {
+               if (!seat) {
+                       seat = wl_registry_bind(registry, id,
+                                       &wl_seat_interface, 1);
+                       if (!seat)
+                               return -1;
+
+                       LOGD("seat(%p)", seat);
+                       keyboard = wl_seat_get_keyboard(seat);
+                       wl_keyboard_add_listener(keyboard, &keyboard_listener,
+                                       NULL);
+                       LOGD("keyboard(%p)", keyboard);
+               }
+       }
+
+       return 0;
+}
+
+static int __on_registry_remover(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       if (keyrouter) {
+               tizen_keyrouter_destroy(keyrouter);
+               keyrouter = NULL;
+       }
+
+       if (input_devmgr) {
+               tizen_input_device_manager_destroy(input_devmgr);
+               input_devmgr = NULL;
+       }
+
+       if (keyboard) {
+               wl_keyboard_destroy(keyboard);
+               keyboard = NULL;
+       }
+
+       return 0;
+}
+
+static int __input_init(void)
+{
+       if (!noti_registered) {
+               amd_noti_listen("wayland.listener.tizen_input_device_manager",
+                               __on_registry_handler);
+               amd_noti_listen("wayland.listener.tizen_keyrouter",
+                               __on_registry_handler);
+               amd_noti_listen("wayland.listener.wl_seat", __on_registry_handler);
+               amd_noti_listen("wayland.listener_remove", __on_registry_remover);
+               amd_noti_listen("app_status.update_status.start", __on_unlock);
+               amd_noti_listen("launch.fail", __on_unlock);
+               amd_noti_listen("launch.prepare.ui.end", __on_lock);
+               noti_registered = true;
+       }
+
+       if (!display) {
+               display = amd_wayland_get_display();
+               if (!display) {
+                       LOGD("Failed to connect to wayland compositor");
+                       return -1;
+               }
+       }
+
+       if (__xkb_init() < 0)
+               return -1;
+
+       LOGD("Connected to wayland compositor!");
+
+       if (input_devmgr == NULL) {
+               LOGE("input_devmgr is null");
+               return -1;
+       }
+
+       if (keyrouter == NULL) {
+               LOGE("keyrouter is null");
+               return -1;
+       }
+
+       if (seat == NULL) {
+               LOGE("seat is null");
+               return -1;
+       }
+
+       if (keyboard == NULL) {
+               LOGE("keyboard is null");
+               return -1;
+       }
+
+       if (tizen_input_device_manager_add_listener(input_devmgr,
+               &input_devmgr_listener, NULL) < 0) {
+               LOGE("Failed to add listener");
+       }
+       wl_display_flush(display);
+       wl_display_roundtrip(display);
+
+       if (g_keymap == NULL) {
+               LOGE("g_keymap is null");
+               return -1;
+       }
+
+       init_done = true;
+
+       return 0;
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       __input_init();
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       __xkb_fini();
+       noti_registered = false;
+       if (sid > 0) {
+               g_source_remove(sid);
+               sid = 0;
+       }
+}
+
+static int __input_lock(void)
+{
+       if (locked)
+               __input_unlock();
+
+       if (!init_done && __input_init() < 0)
+               return -1;
+
+       LOGD("call tizen_input_device_manager_block_events");
+       tizen_input_device_manager_block_events(input_devmgr, 0,
+               TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN |
+               TIZEN_INPUT_DEVICE_MANAGER_CLAS_MOUSE, TIMEOUT_VAL);
+       timer = g_timeout_add(TIMEOUT_VAL, __timeout_handler, NULL);
+       __do_keygrab("XF86Back", TIZEN_KEYROUTER_MODE_EXCLUSIVE);
+       wl_display_roundtrip(display);
+
+       locked = true;
+
+       return 0;
+}
+
+static int __input_unlock(void)
+{
+       if (!locked)
+               return 0;
+
+       if (!init_done && __input_init() < 0)
+               return -1;
+
+       LOGD("call tizen_input_device_manager_unblock_events");
+       tizen_input_device_manager_unblock_events(input_devmgr, 0);
+       __do_keyungrab("XF86Back");
+       wl_display_roundtrip(display);
+
+       locked = false;
+       if (timer > 0) {
+               g_source_remove(timer);
+               timer = 0;
+       }
+
+       return 0;
+}
diff --git a/modules/launchpad/CMakeLists.txt b/modules/launchpad/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c0f48f8
--- /dev/null
@@ -0,0 +1,45 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_LAUNCHPAD "amd-mod-launchpad")
+SET(AMD_MOD_LAUNCHPAD_DIR ${CMAKE_SOURCE_DIR}/modules/launchpad)
+PROJECT(${AMD_MOD_LAUNCHPAD} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_LAUNCHPAD_DIR}/src AMD_MOD_LAUNCHPAD_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_LAUNCHPAD_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       libsystemd
+       security-manager
+       libtzplatform-config
+       libsmack
+       )
+
+pkg_check_modules(amd_mod_launchpad_pkgs REQUIRED ${AMD_MOD_LAUNCHPAD_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_launchpad_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_LAUNCHPAD_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_LAUNCHPAD} ${AMD_MOD_LAUNCHPAD_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_LAUNCHPAD} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_LAUNCHPAD} ${amd_mod_launchpad_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_LAUNCHPAD} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/launchpad/inc/launchpad-private.h b/modules/launchpad/inc/launchpad-private.h
new file mode 100644 (file)
index 0000000..a2838e4
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_LAUNCHPAD"
+
+#define EXPORT __attribute__ ((visibility("default")))
diff --git a/modules/launchpad/src/launchpad.c b/modules/launchpad/src/launchpad.c
new file mode 100644 (file)
index 0000000..3903b52
--- /dev/null
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/signalfd.h>
+#include <sys/stat.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/smack.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <linux/limits.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <systemd/sd-journal.h>
+#include <amd.h>
+#include <bundle_internal.h>
+#include <security-manager.h>
+#include <tzplatform_config.h>
+
+#include "launchpad-private.h"
+
+#define AUL_K_EXEC                     "__AUL_EXEC__"
+#define AUL_K_APPID                    "__AUL_APPID__"
+#define AUL_K_STARTTIME                        "__AUL_STARTTIME__"
+#define AUL_K_HWACC                    "__AUL_HWACC__"
+#define AUL_K_TASKMANAGE               "__AUL_TASKMANAGE__"
+#define AUL_K_PKGID                    "__AUL_PKGID__"
+#define AUL_K_PID                      "__AUL_PID__"
+#define AUL_K_ROOT_PATH                        "__AUL_ROOT_PATH__"
+#define AUL_K_API_VERSION              "__AUL_API_VERSION__"
+#define AUL_K_APP_TYPE                 "__AUL_APP_TYPE__"
+
+#define FORMAT_DBUS_ADDRESS \
+       "kernel:path=/sys/fs/kdbus/%u-user/bus;unix:path=/run/user/%u/bus"
+#define AUL_DBUS_PATH                  "/aul/dbus_handler"
+#define AUL_DBUS_INTERFACE             "org.tizen.aul.signal"
+#define AUL_DBUS_APP_LAUNCH_SIGNAL     "app_launch"
+#define AUL_DBUS_APP_DEAD_SIGNAL       "app_dead"
+
+#define ARG_PATH                       0
+#define PATH_DEV_NULL                  "/dev/null"
+#define PATH_AMD_SOCK                  "/run/aul/daemons/.amd-sock"
+#define APP_STARTUP_SIGNAL             89
+#define CONNECT_RETRY_COUNT            3
+#define CONNECT_RETRY_TIME             (100 * 1000)
+
+typedef struct _app_pkt_t {
+       int cmd;
+       int len;
+       int opt;
+       unsigned char data[1];
+} app_pkt_t;
+
+struct launch_arg {
+       const char *appid;
+       const char *app_path;
+       bundle *b;
+};
+
+struct env_map {
+       const char *key;
+       const char *name;
+};
+
+static struct env_map env_maps[] = {
+       { AUL_K_STARTTIME, "APP_START_TIME" },
+       { AUL_K_HWACC, "HWACC" },
+       { AUL_K_TASKMANAGE, "TASKMANAGE" },
+       { AUL_K_APPID, "AUL_APPID" },
+       { AUL_K_PKGID, "AUL_PKGID" },
+       { AUL_K_APP_TYPE, "RUNTIME_TYPE" },
+       { AUL_K_API_VERSION, "TIZEN_API_VERSION" },
+       { NULL, NULL },
+};
+
+static sigset_t old_mask;
+static guint sigchld_sid;
+static GDBusConnection *conn;
+
+static int __unlink_socket_path(int pid, uid_t uid);
+
+static int __send_signal(const char *path, const char *interface,
+               const char *signal, GVariant *param)
+{
+       GError *err = NULL;
+
+       if (!conn) {
+               conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+               if (!conn) {
+                       LOGE("Failed to get system bus - %s", err->message);
+                       g_error_free(err);
+                       return -1;
+               }
+       }
+
+       if (!g_dbus_connection_emit_signal(conn, NULL, path, interface,
+                               signal, param, &err)) {
+               LOGE("Failed to emit signal(%s) - %s", signal, err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       if (!g_dbus_connection_flush_sync(conn, NULL, &err)) {
+               LOGE("Failed to flush connection - %s", err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void __send_app_launch_signal(int pid, const char *appid)
+{
+       GVariant *param;
+       int r;
+
+       param = g_variant_new("(us)", pid, appid);
+       if (!param) {
+               LOGE("Out of memory");
+               return;
+       }
+
+       r = __send_signal(AUL_DBUS_PATH, AUL_DBUS_INTERFACE,
+                       AUL_DBUS_APP_LAUNCH_SIGNAL, param);
+       if (r < 0)
+               return;
+
+       LOGD("Send app launch signal - pid(%d), appid(%s)", pid, appid);
+}
+
+static void __send_app_dead_signal(int pid)
+{
+       GVariant *param;
+       int r;
+
+       param = g_variant_new("(u)", pid);
+       if (!param) {
+               LOGE("Out of memory");
+               return;
+       }
+
+       r = __send_signal(AUL_DBUS_PATH, AUL_DBUS_INTERFACE,
+                       AUL_DBUS_APP_DEAD_SIGNAL, param);
+       if (r < 0)
+               return;
+
+       LOGD("Send app dead signal - pid(%d)", pid);
+}
+
+static void __init_signal(void)
+{
+       int i;
+
+       for (i = 0; i < _NSIG; ++i) {
+               switch (i) {
+               case SIGQUIT:
+               case SIGILL:
+               case SIGABRT:
+               case SIGBUS:
+               case SIGFPE:
+               case SIGSEGV:
+               case SIGPIPE:
+                       break;
+               default:
+                       signal(i, SIG_DFL);
+                       break;
+               }
+       }
+}
+
+static void __finish_signal(void)
+{
+       int i;
+
+       for (i = 0; i < _NSIG; ++i)
+               signal(i, SIG_DFL);
+}
+
+static int __unblock_sigchld(void)
+{
+       if (sigprocmask(SIG_SETMASK, &old_mask, NULL) < 0) {
+               LOGE("Failed to change blocked signal");
+               return -1;
+       }
+
+       LOGD("Unblock SIGCHLD");
+       return 0;
+}
+
+static void __process_sigchld(struct signalfd_siginfo *siginfo)
+{
+       int status;
+       pid_t child_pid;
+       pid_t child_pgid;
+
+       child_pgid = getpgid(siginfo->ssi_pid);
+       LOGD("pid(%d), pgid(%d), signo(%d), status(%d)",
+                       siginfo->ssi_pid, child_pgid, siginfo->ssi_signo,
+                       siginfo->ssi_status);
+
+       while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
+               if (child_pid == child_pgid)
+                       killpg(child_pgid, SIGKILL);
+
+               __send_app_dead_signal(child_pid);
+               __unlink_socket_path(child_pid, siginfo->ssi_uid);
+       }
+}
+
+static gboolean __handle_sigchld(GIOChannel *io, GIOCondition cond,
+               gpointer data)
+{
+       struct signalfd_siginfo siginfo;
+       ssize_t s;
+       int fd = g_io_channel_unix_get_fd(io);
+
+       do {
+               s = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
+               if (s == 0)
+                       break;
+
+               if (s != sizeof(struct signalfd_siginfo))
+                       break;
+
+               __process_sigchld(&siginfo);
+       } while (s > 0);
+
+       return G_SOURCE_CONTINUE;
+}
+
+static void __destroy_func(gpointer data)
+{
+       GIOChannel *io = (GIOChannel *)data;
+       gint fd;
+
+       if (!io)
+               return;
+
+       fd = g_io_channel_unix_get_fd(io);
+       if (fd > 0)
+               close(fd);
+
+       g_io_channel_unref(io);
+}
+
+static int __init_sigchld_fd(void)
+{
+       int fd;
+       sigset_t mask;
+       GIOChannel *io;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGCHLD);
+
+       if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0)
+               LOGE("Failed to change blocked signals");
+
+       fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
+       if (fd < 0) {
+               LOGE("Failed to create signalfd for SIGCHLD");
+               return -1;
+       }
+
+       io = g_io_channel_unix_new(fd);
+       if (!io) {
+               LOGE("Failed to create g io channel");
+               close(fd);
+               return 0;
+       }
+
+       sigchld_sid = g_io_add_watch_full(io, G_PRIORITY_DEFAULT, G_IO_IN,
+                       __handle_sigchld, io, __destroy_func);
+       if (sigchld_sid == 0) {
+               LOGE("Failed to add sigchld fd wacher");
+               g_io_channel_unref(io);
+               close(fd);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void __set_user_group(void)
+{
+       uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
+       gid_t gid = tzplatform_getgid(TZ_SYS_DEFAULT_USER);
+       const char *user;
+       int r;
+
+       user = tzplatform_getenv(TZ_SYS_DEFAULT_USER);
+       if (!user) {
+               LOGE("Failed to get env - TZ_SYS_DEFAULT_USER");
+               return;
+       }
+
+       r = initgroups(user, gid);
+       if (r != 0)
+               LOGE("Failed to initialize the supplementary group access list");
+
+       r = setregid(gid, gid);
+       if (r != 0)
+               LOGE("Failed to set real and effective group id");
+
+       r = setreuid(uid, uid);
+       if (r != 0)
+               LOGE("Failed to set real and effective user id");
+
+       tzplatform_set_user(uid);
+}
+
+static void __unlink_dir(const char *path)
+{
+       DIR *dp;
+       struct dirent *dentry = NULL;
+       struct stat statbuf;
+       char buf[PATH_MAX];
+       int r;
+
+       dp = opendir(path);
+       if (!dp)
+               return;
+
+       while ((dentry = readdir(dp)) != NULL) {
+               if (!strcmp(dentry->d_name, ".") ||
+                               !strcmp(dentry->d_name, ".."))
+                       continue;
+
+               snprintf(buf, sizeof(buf), "%s/%s", path, dentry->d_name);
+               r = stat(buf, &statbuf);
+               if (r == 0) {
+                       if (S_ISDIR(statbuf.st_mode))
+                               __unlink_dir(buf);
+                       else
+                               unlink(buf);
+               }
+       }
+
+       rmdir(path);
+       closedir(dp);
+}
+
+static int __unlink_socket_path(int pid, uid_t uid)
+{
+       char path[PATH_MAX];
+
+       snprintf(path, sizeof(path), "/run/aul/apps/%d/%d", uid, pid);
+       if (access(path, F_OK) == 0)
+               __unlink_dir(path);
+
+       if (access(path, F_OK) == 0)
+               return -1;
+
+       return 0;
+}
+
+static void __redirect_stdio(const char *ident)
+{
+       int fd;
+
+       /* stdin */
+       fd = open(PATH_DEV_NULL, O_RDONLY | O_NOCTTY);
+       if (fd < 0) {
+               LOGW("Failed to open /dev/null - err(%d)", errno);
+               return;
+       }
+       if (dup2(fd, STDIN_FILENO) < 0) {
+               LOGW("Failed to duplicate fd - oldfd(%d), newfd(%d)",
+                               fd, STDIN_FILENO);
+       }
+       close(fd);
+
+       /* stdout */
+       fd = sd_journal_stream_fd(ident, LOG_INFO, false);
+       if (fd < 0) {
+               LOGW("Failed to connect journal socket - err(%d)", errno);
+               fd = open(PATH_DEV_NULL, O_WRONLY | O_NOCTTY);
+               if (fd < 0) {
+                       LOGW("Failed to open /dev/null - err(%d)", errno);
+                       return;
+               }
+       }
+       if (dup2(fd, STDOUT_FILENO) < 0) {
+               LOGW("Failed to duplicate fd - oldfd(%d), newfd(%d)",
+                               fd, STDOUT_FILENO);
+       }
+       close(fd);
+
+       /* stderr */
+       fd = sd_journal_stream_fd(ident, LOG_INFO, false);
+       if (fd < 0) {
+               LOGW("Failed to connect journal socket - err(%d)", errno);
+               fd = open(PATH_DEV_NULL, O_WRONLY | O_NOCTTY);
+               if (fd < 0) {
+                       LOGW("Failed to open /dev/null - err(%d)", errno);
+                       return;
+               }
+       }
+
+       if (dup2(fd, STDERR_FILENO) < 0) {
+               LOGW("Failed to duplicate fd - oldfd(%d), newfd(%d)",
+                               fd, STDERR_FILENO);
+       }
+       close(fd);
+}
+
+static void __set_env(bundle *b)
+{
+       const char *val;
+       char buf[PATH_MAX];
+       int i;
+
+       for (i = 0; env_maps[i].key; ++i) {
+               val = bundle_get_val(b, env_maps[i].key);
+               if (val)
+                       setenv(env_maps[i].name, val, 1);
+       }
+
+       val = bundle_get_val(b, AUL_K_ROOT_PATH);
+       if (val) {
+               setenv("AUL_ROOT_PATH", val, 1);
+               /* for backward compatibility */
+               snprintf(buf, sizeof(buf), "%s/lib/", val);
+               setenv("LD_LIBRARY_PATH", buf, 1);
+       }
+
+       val = tzplatform_getenv(TZ_USER_HOME);
+       if (val)
+               setenv("HOME", val, 1);
+
+       val = tzplatform_getenv(TZ_SYS_DEFAULT_USER);
+       if (val) {
+               setenv("LOGNAME", val, 1);
+               setenv("USER", val, 1);
+       }
+
+       snprintf(buf, sizeof(buf), "%d", getpid());
+       setenv("AUL_PID", buf, 1);
+
+       snprintf(buf, sizeof(buf), "/run/user/%d", getuid());
+       setenv("XDG_RUNTIME_DIR", buf, 1);
+
+       snprintf(buf, sizeof(buf), "/run/user_ext/%d", getuid());
+       setenv("XDG_RUNTIME_EXT_DIR", buf, 1);
+
+       snprintf(buf, sizeof(buf), FORMAT_DBUS_ADDRESS, getuid(), getuid());
+       setenv("DBUS_SESSION_BUS_ADDRESS", buf, 1);
+}
+
+static int __send_cmd_to_amd(int cmd)
+{
+       struct sockaddr_un addr = {0,};
+       int retry = CONNECT_RETRY_COUNT;
+       app_pkt_t pkt = {0,};
+       int fd;
+       int ret;
+
+       fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       /*  support above version 2.6.27*/
+       if (fd < 0) {
+               if (errno == EINVAL) {
+                       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+                       if (fd < 0) {
+                               LOGE("second chance - socket create error");
+                               return -1;
+                       }
+               } else {
+                       LOGE("socket error");
+                       return -1;
+               }
+       }
+
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", PATH_AMD_SOCK);
+       while (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+               if (errno != ETIMEDOUT || retry <= 0) {
+                       LOGE("Failed to connect error(%d)", errno);
+                       close(fd);
+                       return -1;
+               }
+
+               usleep(CONNECT_RETRY_TIME);
+               --retry;
+               LOGD("re-connect to %s (%d)", addr.sun_path, retry);
+       }
+
+       pkt.cmd = cmd;
+       ret = send(fd, &pkt, sizeof(app_pkt_t), MSG_NOSIGNAL);
+       if (ret <= 0) {
+               LOGE("Failed to send cmd(%d), errno(%d)", cmd, errno);
+               close(fd);
+               return -ECOMM;
+       }
+       close(fd);
+
+       return 0;
+}
+
+static int __prepare_exec(struct launch_arg *arg)
+{
+       char *name;
+       int r;
+
+       /* Set new session ID & new process group ID*/
+       /* In linux, child can set new session ID without check permission */
+       setsid();
+
+       /* Set privileges */
+       r = security_manager_prepare_app(arg->appid);
+       if (r != SECURITY_MANAGER_SUCCESS) {
+               LOGE("Failed to set privileges");
+               return -1;
+       }
+
+       __send_cmd_to_amd(APP_STARTUP_SIGNAL);
+
+       name = basename(arg->app_path);
+       if (!name) {
+               LOGE("Failed to parse name");
+               return -1;
+       }
+
+       __redirect_stdio(name);
+       prctl(PR_SET_NAME, name);
+       __set_env(arg->b);
+
+       return 0;
+}
+
+static void __close_all_fds(void)
+{
+       DIR *dp;
+       struct dirent *dentry = NULL;
+       int fd;
+       int max_fd = sysconf(_SC_OPEN_MAX);
+
+       dp = opendir("/proc/self/fd");
+       if (!dp) {
+               for (fd = 3; fd < max_fd; ++fd)
+                       close(fd);
+               return;
+       }
+
+       while ((dentry = readdir(dp)) != NULL) {
+               if (!isdigit(dentry->d_name[0]))
+                       continue;
+
+               fd = atoi(dentry->d_name);
+               if (fd < 3 || fd >= max_fd)
+                       continue;
+
+               if (fd == dirfd(dp))
+                       continue;
+
+               close(fd);
+       }
+       closedir(dp);
+}
+
+static int __exec_app_process(struct launch_arg *arg)
+{
+       int app_argc;
+       char **app_argv = NULL;
+       int i;
+       int r;
+
+       __unblock_sigchld();
+       __finish_signal();
+       __set_user_group();
+
+       LOGD("appid(%s), pid(%d), uid(%d)", arg->appid, getpid(), getuid());
+
+       r = __unlink_socket_path(getpid(), getuid());
+       if (r < 0) {
+               LOGE("Failed to delete socket path");
+               return r;
+       }
+
+       r = __prepare_exec(arg);
+       if (r < 0) {
+               LOGE("Failed to prepare exec");
+               return r;
+       }
+
+       app_argc = bundle_export_to_argv(arg->b, &app_argv);
+       if (app_argc <= 0) {
+               LOGE("Failed to export bundle data");
+               return -1;
+       }
+       app_argv[ARG_PATH] = strdup(arg->app_path);
+
+       for (i = 0; i < app_argc; ++i)
+               LOGD("input argument %d: %s##", i, app_argv[i]);
+
+       __close_all_fds();
+
+       r = execv(app_argv[ARG_PATH], app_argv);
+       if (r < 0) {
+               fprintf(stderr, "Failed to execute %s - err(%d)",
+                               app_argv[ARG_PATH], errno);
+       }
+
+       return r;
+}
+
+static int __launcher(bundle *b, uid_t uid, void *user_data)
+{
+       struct launch_arg arg;
+       int pid;
+       int r;
+       uid_t default_uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
+
+       if (!b) {
+               LOGE("Invalid parameter");
+               return -1;
+       }
+
+       if (uid != default_uid) {
+               LOGE("uid(%u) is not default uid(%u)", uid, default_uid);
+               return -1;
+       }
+
+       arg.appid = bundle_get_val(b, AUL_K_APPID);
+       arg.app_path = bundle_get_val(b, AUL_K_EXEC);
+       arg.b = b;
+
+       pid = fork();
+       if (pid == 0) {
+               r = __exec_app_process(&arg);
+               exit(r);
+       } else if (pid > 0) {
+               LOGD("==> real launch pid: %d(%s)", pid, arg.app_path);
+               __send_app_launch_signal(pid, arg.appid);
+       } else {
+               LOGE("Failed to fork process");
+       }
+
+       return pid;
+}
+
+static gboolean __send_startup_finished(gpointer data)
+{
+       uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
+
+       amd_noti_send("startup.finished", (int)uid, 0, NULL, NULL);
+       return G_SOURCE_REMOVE;
+}
+
+static void __create_user_directories(void)
+{
+       char buf[PATH_MAX];
+       int pid;
+
+       pid = fork();
+       if (pid == 0) {
+               __unblock_sigchld();
+               __finish_signal();
+               __set_user_group();
+
+               snprintf(buf, sizeof(buf), "/run/aul/apps/%u", getuid());
+               if (mkdir(buf, 0700) < 0)
+                       LOGW("Failed to create %s", buf);
+               if (smack_setlabel(buf, "User", SMACK_LABEL_ACCESS))
+                       LOGW("Failed to change smack");
+
+               snprintf(buf, sizeof(buf), "/run/aul/dbspace/%u", getuid());
+               if (mkdir(buf, 0701) < 0)
+                       LOGW("Failed to create %s", buf);
+               if (smack_setlabel(buf, "User::Home", SMACK_LABEL_ACCESS))
+                       LOGW("Failed to change smack");
+
+               exit(EXIT_SUCCESS);
+       }
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       int r;
+
+       LOGD("launchpad init");
+
+       r = amd_launchpad_set_launcher(__launcher, NULL);
+       if (r < 0)
+               return -1;
+
+       r = __init_sigchld_fd();
+       if (r < 0)
+               return -1;
+
+       __init_signal();
+       __create_user_directories();
+       g_idle_add(__send_startup_finished, NULL);
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       LOGD("launchpad fini");
+
+       if (conn) {
+               g_object_unref(conn);
+               conn = NULL;
+       }
+
+       if (sigchld_sid > 0) {
+               g_source_remove(sigchld_sid);
+               sigchld_sid = 0;
+       }
+
+       amd_launchpad_set_launcher(NULL, NULL);
+}
diff --git a/modules/rua/CMakeLists.txt b/modules/rua/CMakeLists.txt
new file mode 100644 (file)
index 0000000..23d823e
--- /dev/null
@@ -0,0 +1,43 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_RUA "amd-mod-rua")
+SET(AMD_MOD_RUA_DIR ${CMAKE_SOURCE_DIR}/modules/rua)
+PROJECT(${AMD_MOD_RUA} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_RUA_DIR}/src AMD_MOD_RUA_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_RUA_PKG_CHECK_MODULES
+       dlog
+       rua
+       glib-2.0
+       gio-2.0
+       aul
+       )
+
+pkg_check_modules(amd_mod_rua_pkgs REQUIRED ${AMD_MOD_RUA_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_rua_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_RUA_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_RUA} ${AMD_MOD_RUA_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_RUA} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_RUA} ${amd_mod_rua_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_RUA} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/rua/inc/amd_rua.h b/modules/rua/inc/amd_rua.h
new file mode 100644 (file)
index 0000000..c3d1ee4
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_RUA"
+
+#define EXPORT __attribute__ ((visibility("default")))
+
diff --git a/modules/rua/src/amd_rua.c b/modules/rua/src/amd_rua.c
new file mode 100644 (file)
index 0000000..7cb7769
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <aul.h>
+#include <aul_sock.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <rua_internal.h>
+#include <rua_stat_internal.h>
+#include <dlog.h>
+
+#include "amd.h"
+#include "amd_rua.h"
+
+#define PATH_RUN       "/run"
+#define FILE_E_IMG     ".e-img"
+#define PATH_RUN_E_IMG PATH_RUN "/" FILE_E_IMG
+#define MULTI_INSTANCE_SHORTCUT "multi-instance-shortcut"
+#define QUERY_KEY_ID "id="
+#define QUERY_KEY_ICON "icon="
+#define QUERY_KEY_NAME "name="
+#define PENDING_REQUEST_TIMEOUT 5000 /* msec */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define AUL_SVC_K_URI          "__APP_SVC_URI__"
+#define AUL_SVC_K_LAUNCH_MODE   "__APP_SVC_LAUNCH_MODE__"
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_RUA"
+
+struct rua_info_s {
+       uid_t uid;
+       char *appid;
+       char *app_path;
+       char *instance_id;
+       char *image_path;
+};
+
+typedef struct _rua_stat_pkt_t {
+       pid_t pid;
+       uid_t uid;
+       char *stat_tag;
+       char *stat_caller;
+       char *appid;
+       char *instance_id;
+       char *instance_name;
+       char *icon;
+       char *uri;
+       gboolean is_group_app;
+       char *data;
+       int len;
+} rua_stat_pkt_t;
+
+struct instance_info {
+       char *id;
+       char *name;
+       char *icon;
+       char *uri;
+};
+
+static int __dir_wd;
+static int __img_wd;
+static GHashTable *__rua_tbl;
+
+static bool __is_group_request(bundle *kb, uid_t uid)
+{
+       const char *str;
+       const char *mode;
+       const char *appid;
+       amd_appinfo_h ai;
+
+       if (kb == NULL)
+               return false;
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       if (appid == NULL)
+               return false;
+
+       ai = amd_appinfo_find(uid, appid);
+       mode = amd_appinfo_get_value(ai, AMD_AIT_LAUNCH_MODE);
+       if (mode != NULL && strcmp(mode, "caller") == 0) {
+               str = bundle_get_val(kb, AUL_SVC_K_LAUNCH_MODE);
+               if (str != NULL && strcmp(str, "group") == 0)
+                       return true;
+       } else if (mode != NULL && strcmp(mode, "group") == 0) {
+               return true;
+       }
+
+       return false;
+}
+
+static void __free_rua_stat_pkt(void *data)
+{
+       rua_stat_pkt_t *pkt = data;
+
+       if (pkt == NULL)
+               return;
+
+       if (pkt->data)
+               free(pkt->data);
+       if (pkt->uri)
+               free(pkt->uri);
+       if (pkt->icon)
+               free(pkt->icon);
+       if (pkt->instance_name)
+               free(pkt->instance_name);
+       if (pkt->instance_id)
+               free(pkt->instance_id);
+       if (pkt->appid)
+               free(pkt->appid);
+       if (pkt->stat_caller)
+               free(pkt->stat_caller);
+       if (pkt->stat_tag)
+               free(pkt->stat_tag);
+
+       free(pkt);
+}
+
+static rua_stat_pkt_t *__create_rua_stat_pkt(amd_request_h req, bundle *kb,
+               const char *appid, struct instance_info *info, int pid)
+{
+       const char *stat_caller;
+       const char *stat_tag;
+       rua_stat_pkt_t *rua_stat_item;
+       int len = amd_request_get_len(req);
+
+       rua_stat_item = calloc(1, sizeof(rua_stat_pkt_t));
+       if (rua_stat_item == NULL) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       rua_stat_item->pid = pid;
+
+       if (len > 0) {
+               rua_stat_item->data = calloc(len + 1, sizeof(char));
+               if (rua_stat_item->data == NULL) {
+                       LOGE("out of memory");
+                       __free_rua_stat_pkt(rua_stat_item);
+                       return NULL;
+               }
+               memcpy(rua_stat_item->data, amd_request_get_raw(req),
+                               amd_request_get_len(req));
+       }
+       rua_stat_item->len = len;
+
+       stat_caller = bundle_get_val(kb, AUL_SVC_K_RUA_STAT_CALLER);
+       if (stat_caller != NULL) {
+               rua_stat_item->stat_caller = strdup(stat_caller);
+               if (rua_stat_item->stat_caller == NULL) {
+                       LOGE("Out of memory");
+                       __free_rua_stat_pkt(rua_stat_item);
+                       return NULL;
+               }
+       }
+
+       stat_tag = bundle_get_val(kb, AUL_SVC_K_RUA_STAT_TAG);
+       if (stat_tag != NULL) {
+               rua_stat_item->stat_tag = strdup(stat_tag);
+               if (rua_stat_item->stat_tag == NULL) {
+                       LOGE("Out of memory");
+                       __free_rua_stat_pkt(rua_stat_item);
+                       return NULL;
+               }
+
+       }
+
+       if (appid) {
+               rua_stat_item->appid = strdup(appid);
+               if (rua_stat_item->appid == NULL) {
+                       LOGE("Out of memory");
+                       __free_rua_stat_pkt(rua_stat_item);
+                       return NULL;
+               }
+       }
+
+       if (info->id) {
+               rua_stat_item->instance_id = strdup(info->id);
+               if (rua_stat_item->instance_id == NULL) {
+                       LOGE("Out of memory");
+                       __free_rua_stat_pkt(rua_stat_item);
+                       return NULL;
+               }
+       }
+
+       if (info->name) {
+               rua_stat_item->instance_name = strdup(info->name);
+               if (rua_stat_item->instance_name == NULL) {
+                       LOGE("Out of memory");
+                       __free_rua_stat_pkt(rua_stat_item);
+                       return NULL;
+               }
+       }
+
+       if (info->icon) {
+               rua_stat_item->icon = strdup(info->icon);
+               if (rua_stat_item->icon == NULL) {
+                       LOGE("Out of memory");
+                       __free_rua_stat_pkt(rua_stat_item);
+                       return NULL;
+               }
+       }
+
+       if (info->uri) {
+               rua_stat_item->uri = strdup(info->uri);
+               if (rua_stat_item->uri == NULL) {
+                       LOGE("Out of memory");
+                       __free_rua_stat_pkt(rua_stat_item);
+                       return NULL;
+               }
+       }
+
+       rua_stat_item->uid = amd_request_get_target_uid(req);
+       rua_stat_item->is_group_app = __is_group_request(kb,
+                       rua_stat_item->uid);
+
+       return rua_stat_item;
+}
+
+static const char *__rua_get_image_path(int pid)
+{
+       struct rua_info_s *info;
+
+       if (__rua_tbl == NULL)
+               return NULL;
+
+       info = (struct rua_info_s *)g_hash_table_lookup(__rua_tbl,
+                       GINT_TO_POINTER(pid));
+       if (info == NULL)
+               return NULL;
+
+       return info->image_path;
+}
+
+static gboolean __add_history_handler(gpointer user_data)
+{
+       struct rua_rec rec = { 0, };
+       int ret;
+       amd_appinfo_h ai;
+       rua_stat_pkt_t *pkt = (rua_stat_pkt_t *)user_data;
+
+       if (!pkt)
+               return FALSE;
+
+       if (!pkt->is_group_app) {
+               ai = amd_appinfo_find(pkt->uid, pkt->appid);
+
+               rec.pkg_name = pkt->appid;
+               rec.app_path = (char *)amd_appinfo_get_value(ai, AMD_AIT_EXEC);
+
+               if (pkt->len > 0)
+                       rec.arg = pkt->data;
+
+               rec.launch_time = time(NULL);
+               rec.instance_id = pkt->instance_id;
+               rec.instance_name = pkt->instance_name;
+               rec.icon = pkt->icon;
+               rec.uri = pkt->uri;
+               rec.image = (char *)__rua_get_image_path(pkt->pid);
+
+               SECURE_LOGD("add rua history %s %s",
+                               rec.pkg_name, rec.app_path);
+               ret = rua_usr_db_add_history(&rec, pkt->uid);
+               if (ret == -1)
+                       LOGD("rua add history error");
+       }
+
+       if (pkt->stat_caller != NULL && pkt->stat_tag != NULL) {
+               SECURE_LOGD("rua_stat_caller: %s, rua_stat_tag: %s",
+                               pkt->stat_caller, pkt->stat_tag);
+               rua_stat_usr_db_update(pkt->stat_caller, pkt->stat_tag,
+                               pkt->uid);
+       }
+
+       __free_rua_stat_pkt(pkt);
+
+       return FALSE;
+}
+
+static void __destroy_rua_info(gpointer data)
+{
+       struct rua_info_s *info = (struct rua_info_s *)data;
+
+       if (info == NULL)
+               return;
+
+       if (info->image_path) {
+               unlink(info->image_path); /* Delete image file */
+               free(info->image_path);
+       }
+
+       if (info->instance_id)
+               free(info->instance_id);
+
+       if (info->app_path)
+               free(info->app_path);
+
+       if (info->appid)
+               free(info->appid);
+
+       free(info);
+}
+
+static struct rua_info_s *__create_rua_info(const char *appid,
+               const char *app_path, const char *instance_id,
+               uid_t uid)
+{
+       struct rua_info_s *info;
+
+       info = calloc(1, sizeof(struct rua_info_s));
+       if (info == NULL) {
+               LOGE("Out of memory");
+               return NULL;
+       }
+
+       info->appid = strdup(appid);
+       if (info->appid == NULL) {
+               LOGE("Out of memory");
+               __destroy_rua_info(info);
+               return NULL;
+       }
+
+       info->app_path = strdup(app_path);
+       if (info->app_path == NULL) {
+               LOGE("Out of memory");
+               __destroy_rua_info(info);
+               return NULL;
+       }
+
+       if (instance_id) {
+               info->instance_id = strdup(instance_id);
+               if (info->instance_id == NULL) {
+                       LOGE("Out of memory");
+                       __destroy_rua_info(info);
+                       return NULL;
+               }
+       }
+
+       info->uid = uid;
+
+       return info;
+}
+
+static int __rua_add_info(int pid, bool new_instance)
+{
+       struct rua_info_s *info;
+       amd_app_status_h app_status;
+       const char *appid;
+       const char *app_path;
+       const char *instance_id;
+       uid_t uid;
+
+       if (__rua_tbl == NULL)
+               return 0;
+
+       app_status = amd_app_status_find_by_pid(pid);
+       if (app_status == NULL)
+               return -1;
+
+       appid = amd_app_status_get_appid(app_status);
+       app_path = amd_app_status_get_app_path(app_status);
+       uid = amd_app_status_get_uid(app_status);
+
+       if (new_instance)
+               instance_id = amd_app_status_get_instance_id(app_status);
+       else
+               instance_id = NULL;
+
+       info = __create_rua_info(appid, app_path, instance_id, uid);
+       if (info == NULL)
+               return -1;
+
+       if (g_hash_table_contains(__rua_tbl, GINT_TO_POINTER(pid)))
+               g_hash_table_replace(__rua_tbl, GINT_TO_POINTER(pid), info);
+       else
+               g_hash_table_insert(__rua_tbl, GINT_TO_POINTER(pid), info);
+
+       return 0;
+}
+
+static gboolean __foreach_remove_by_uid(gpointer key, gpointer value,
+               gpointer data)
+{
+       struct rua_info_s *info = (struct rua_info_s *)value;
+       uid_t uid = GPOINTER_TO_UINT(data);
+
+       if (info->uid == uid)
+               return TRUE;
+
+       return FALSE;
+}
+
+static gboolean __foreach_remove_by_appid(gpointer key, gpointer value,
+               gpointer data)
+{
+       struct rua_info_s *info = (struct rua_info_s *)value;
+       const char *appid = (const char *)data;
+
+       if (strcmp(info->appid, appid) == 0)
+               return TRUE;
+
+       return FALSE;
+}
+
+static gboolean __foreach_remove_by_app_path(gpointer key, gpointer value,
+               gpointer data)
+{
+       struct rua_info_s *info = (struct rua_info_s *)value;
+       const char *app_path = (const char *)data;
+
+       if (strcmp(info->app_path, app_path) == 0)
+               return TRUE;
+
+       return FALSE;
+}
+
+static gboolean __foreach_remove_by_instance_id(gpointer key, gpointer value,
+               gpointer data)
+{
+       struct rua_info_s *info = (struct rua_info_s *)value;
+       const char *instance_id = (const char *)data;
+
+       if (info->instance_id && strcmp(info->instance_id, instance_id) == 0)
+               return TRUE;
+
+       return FALSE;
+}
+
+static int __delete_rua_info(bundle *b, uid_t uid)
+{
+       char *appid = NULL;
+       char *app_path = NULL;
+       char *instance_id = NULL;
+
+       if (b) {
+               bundle_get_str(b, AUL_K_RUA_PKGNAME, &appid);
+               bundle_get_str(b, AUL_K_RUA_APPPATH, &app_path);
+               bundle_get_str(b, AUL_K_RUA_INSTANCE_ID, &instance_id);
+       }
+
+       if (appid) {
+               g_hash_table_foreach_remove(__rua_tbl,
+                               __foreach_remove_by_appid, appid);
+       } else if (app_path) {
+               g_hash_table_foreach_remove(__rua_tbl,
+                               __foreach_remove_by_app_path, app_path);
+       } else if (instance_id) {
+               g_hash_table_foreach_remove(__rua_tbl,
+                               __foreach_remove_by_instance_id, instance_id);
+       } else {
+               g_hash_table_foreach_remove(__rua_tbl,
+                               __foreach_remove_by_uid, GUINT_TO_POINTER(uid));
+       }
+
+       return 0;
+}
+
+static void __update_img_file(const char *img)
+{
+       int r;
+       int pid = -1;
+       unsigned int rid = 0;
+       int num = -1;
+       char buf[PATH_MAX];
+       struct rua_info_s *info;
+
+       sscanf(img, "win_%d_%u-%d.png", &pid, &rid, &num);
+       if (pid <= 0)
+               return;
+
+       snprintf(buf, sizeof(buf), "%s/%s", PATH_RUN_E_IMG, img);
+
+       info = (struct rua_info_s *)g_hash_table_lookup(__rua_tbl,
+                       GINT_TO_POINTER(pid));
+       if (info == NULL) {
+               unlink(buf);
+               return;
+       }
+
+       if (info->image_path) {
+               if (strcmp(info->image_path, buf) == 0)
+                       return;
+
+               unlink(info->image_path);
+               free(info->image_path);
+       }
+
+       r = rua_usr_db_update_image(info->appid, info->instance_id,
+                       buf, info->uid);
+       if (r < 0)
+               LOGW("Failed to update image path - appid(%s)", info->appid);
+
+       info->image_path = strdup(buf);
+       if (info->image_path == NULL)
+               LOGE("Out of memory");
+}
+
+static void __find_imgs(void)
+{
+       DIR *dp;
+       struct dirent *dentry = NULL;
+       char buf[PATH_MAX];
+       struct stat statbuf;
+       int r;
+
+       dp = opendir(PATH_RUN_E_IMG);
+       if (dp == NULL)
+               return;
+
+       while ((dentry = readdir(dp))) {
+               if (!strcmp(dentry->d_name, ".") ||
+                               !strcmp(dentry->d_name, ".."))
+                       continue;
+
+               snprintf(buf, sizeof(buf), "%s/%s",
+                               PATH_RUN_E_IMG, dentry->d_name);
+               r = stat(buf, &statbuf);
+               if (r == 0) {
+                       if (S_ISREG(statbuf.st_mode))
+                               __update_img_file(buf);
+               }
+       }
+       closedir(dp);
+}
+
+static bool __img_monitor_cb(const char *event_name, void *data)
+{
+       if (event_name) {
+               __update_img_file(event_name);
+               LOGD("%s is created", event_name);
+       }
+
+       return true;
+}
+
+static bool __dir_monitor_cb(const char *event_name, void *data)
+{
+       if (event_name == NULL)
+               return true;
+
+       if (strcmp(event_name, FILE_E_IMG) == 0) {
+               __img_wd = amd_inotify_add_watch(PATH_RUN_E_IMG, IN_CREATE,
+                               __img_monitor_cb, NULL);
+               if (__img_wd < 0)
+                       LOGE("Failed to add inotify watch");
+               else
+                       __find_imgs();
+
+               __dir_wd = 0;
+               return false;
+       }
+
+       return true;
+}
+
+static int __dispatch_update_rua_stat(amd_request_h req)
+{
+       int result;
+       char *caller = NULL;
+       char *tag = NULL;
+       uid_t uid = amd_request_get_target_uid(req);
+       bundle *kb = amd_request_get_bundle(req);
+
+       bundle_get_str(kb, AUL_SVC_K_RUA_STAT_CALLER, &caller);
+       bundle_get_str(kb, AUL_SVC_K_RUA_STAT_TAG, &tag);
+       result = rua_stat_usr_db_update(caller, tag, uid);
+       LOGD("rua_stat_usr_db_update - uid(%d), result(%d)", uid, result);
+       amd_request_send_result(req, result);
+
+       return 0;
+}
+
+static int __dispatch_add_history(amd_request_h req)
+{
+       int result;
+       struct rua_rec rec = {0,};
+       char *time_str;
+       uid_t uid = amd_request_get_target_uid(req);
+       bundle *b = amd_request_get_bundle(req);
+
+       bundle_get_str(b, AUL_K_RUA_PKGNAME, &rec.pkg_name);
+       bundle_get_str(b, AUL_K_RUA_APPPATH, &rec.app_path);
+       bundle_get_str(b, AUL_K_RUA_ARG, &rec.arg);
+       bundle_get_str(b, AUL_K_RUA_TIME, &time_str);
+       if (time_str != NULL)
+               rec.launch_time = atoi(time_str);
+       else
+               rec.launch_time = (int)time(NULL);
+       bundle_get_str(b, AUL_K_RUA_INSTANCE_ID, &rec.instance_id);
+       bundle_get_str(b, AUL_K_RUA_INSTANCE_NAME, &rec.instance_name);
+       bundle_get_str(b, AUL_K_RUA_ICON, &rec.icon);
+       bundle_get_str(b, AUL_K_RUA_URI, &rec.uri);
+
+       result = rua_usr_db_add_history(&rec, uid);
+       LOGD("rua_usr_db_add_history - uid(%d), result(%d)", uid, result);
+       amd_request_send_result(req, result);
+
+       return 0;
+}
+
+static int __dispatch_remove_history(amd_request_h req)
+{
+       int result;
+       bundle *b = amd_request_get_bundle(req);
+       uid_t uid = amd_request_get_target_uid(req);
+
+       result = rua_usr_db_delete_history(b, uid);
+       LOGD("rua_usr_db_delete_history - uid(%d), result(%d)", uid, result);
+       amd_request_send_result(req, result);
+       __delete_rua_info(b, uid);
+
+       return 0;
+}
+
+static amd_request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = APP_UPDATE_RUA_STAT,
+               .callback = __dispatch_update_rua_stat
+       },
+       {
+               .cmd = APP_ADD_HISTORY,
+               .callback = __dispatch_add_history
+       },
+       {
+               .cmd = APP_REMOVE_HISTORY,
+               .callback = __dispatch_remove_history
+       },
+
+};
+
+static amd_cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = APP_UPDATE_RUA_STAT,
+               .checker = amd_cynara_simple_checker,
+               .data = PRIVILEGE_PLATFORM
+       },
+       {
+               .cmd = APP_ADD_HISTORY,
+               .checker = amd_cynara_simple_checker,
+               .data = PRIVILEGE_PLATFORM
+       },
+       {
+               .cmd = APP_REMOVE_HISTORY,
+               .checker = amd_cynara_simple_checker,
+               .data = PRIVILEGE_PLATFORM
+       },
+};
+
+static int __on_user_init(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       rua_usr_db_delete_history(NULL, arg1);
+
+       return AMD_NOTI_CONTINUE;
+}
+
+static int __on_user_logout(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       uid_t uid = (uid_t)arg1;
+
+       if (__rua_tbl == NULL)
+               return AMD_NOTI_CONTINUE;
+
+       g_hash_table_foreach_remove(__rua_tbl,
+                       __foreach_remove_by_uid, GUINT_TO_POINTER(uid));
+
+       return AMD_NOTI_CONTINUE;
+}
+
+static void __free_instance_info(struct instance_info *info)
+{
+       if (info->uri) {
+               free(info->uri);
+               info->uri = NULL;
+       }
+
+       if (info->id) {
+               free(info->id);
+               info->id = NULL;
+       }
+
+       if (info->icon) {
+               free(info->icon);
+               info->icon = NULL;
+       }
+
+       if (info->name) {
+               free(info->name);
+               info->name = NULL;
+       }
+}
+
+static char *__get_value_from_query(const char *src, const char *key)
+{
+       int src_len = strlen(src);
+       int key_len = strlen(key);
+
+       if (src_len > key_len) {
+               if (strncmp(src, key, key_len) == 0)
+                       return g_uri_unescape_string(src + key_len, NULL);
+       }
+
+       return NULL;
+}
+
+static int __get_instance_info(bundle *kb, struct instance_info *info)
+{
+       const char *uri;
+       gchar *scheme;
+       gchar *query;
+       char *token;
+       char *dup_uri;
+
+       uri = bundle_get_val(kb, AUL_SVC_K_URI);
+       if (uri == NULL)
+               return -1;
+
+       scheme = g_uri_parse_scheme(uri);
+       if (scheme == NULL)
+               return -1;
+
+       if (strcmp(scheme, MULTI_INSTANCE_SHORTCUT) != 0) {
+               g_free(scheme);
+               return -1;
+       }
+       g_free(scheme);
+
+       dup_uri = strdup(uri);
+       if (dup_uri == NULL) {
+               LOGE("Out of memory");
+               return -1;
+       }
+
+       info->uri = strdup(uri);
+       if (info->uri == NULL) {
+               LOGE("Out of memory");
+               free(dup_uri);
+               return -1;
+       }
+
+       query = index(dup_uri, '?');
+       if (query == NULL || query + 1 == NULL) {
+               __free_instance_info(info);
+               free(dup_uri);
+               return -1;
+       }
+
+       token = strtok(query + 1, "&");
+       while (token != NULL) {
+               if (info->id == NULL)
+                       info->id = __get_value_from_query(token, QUERY_KEY_ID);
+               if (info->icon == NULL) {
+                       info->icon = __get_value_from_query(token,
+                                       QUERY_KEY_ICON);
+               }
+               if (info->name == NULL) {
+                       info->name = __get_value_from_query(token,
+                                       QUERY_KEY_NAME);
+               }
+
+               token = strtok(NULL, "&");
+       }
+       free(dup_uri);
+
+       if (info->id == NULL || info->icon == NULL || info->name == NULL) {
+               LOGW("Failed to get instance info");
+               __free_instance_info(info);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __on_app_start(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       const char *appid;
+       const char *instance_id;
+       int ret;
+       bundle *kb;
+       bool pending = false;
+       bool bg_launch = false;
+       bool new_instance = false;
+       struct instance_info info = {0,};
+       amd_request_reply_h reply;
+       rua_stat_pkt_t *rua = NULL;
+       amd_request_h req = arg3;
+
+       kb = amd_request_get_bundle(req);
+       if (kb == NULL)
+               return AMD_NOTI_STOP;
+
+       if (__get_instance_info(kb, &info) == 0) {
+               bundle_del(kb, AUL_K_INSTANCE_ID);
+               bundle_add(kb, AUL_K_INSTANCE_ID, info.id);
+               new_instance = true;
+               LOGD("Multiple instance launch - id(%s), name(%s), icon(%s)",
+                               info.id, info.name, info.icon);
+       } else {
+               instance_id = bundle_get_val(kb, AUL_K_INSTANCE_ID);
+               if (instance_id) {
+                       info.id = strdup(instance_id);
+                       if (info.id == NULL)
+                               LOGW("Out of memory");
+                       LOGD("Multiple instance launch - id(%s)", info.id);
+               }
+       }
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       ret = amd_launch_start_app(appid, req, &pending, &bg_launch, new_instance);
+       if (ret <= 0)
+               amd_noti_send("launch.fail", ret, 0, NULL, NULL);
+
+       /* add pending list to wait app launched successfully */
+       if (pending) {
+               if (!bg_launch) {
+                       rua = __create_rua_stat_pkt(req, kb, appid, &info, ret);
+                       if (rua && !rua->is_group_app)
+                               __rua_add_info(ret, new_instance);
+               }
+
+               reply = amd_request_reply_create_full(req, ret, ret,
+                               amd_request_get_cmd(req), rua,
+                               __free_rua_stat_pkt);
+               if (reply == NULL) {
+                       __free_instance_info(&info);
+                       return AMD_NOTI_STOP;
+               }
+
+               if (amd_request_reply_append(ret, reply) < 0) {
+                       amd_request_send_result(req, ret);
+                       __free_instance_info(&info);
+                       return AMD_NOTI_STOP;
+               }
+
+               __free_instance_info(&info);
+               return AMD_NOTI_STOP;
+       }
+
+       if (ret > 0 && !bg_launch) {
+               rua = __create_rua_stat_pkt(req, kb, appid, &info, ret);
+               if (rua == NULL) {
+                       __free_instance_info(&info);
+                       return AMD_NOTI_STOP;
+               }
+               g_timeout_add(1500, __add_history_handler, rua);
+       }
+       __free_instance_info(&info);
+
+       return AMD_NOTI_STOP;
+}
+
+static int __reply_foreach_cb(void *data)
+{
+       if (data) {
+               g_timeout_add(1500, __add_history_handler, data);
+               return 0;
+       }
+
+       return -1;
+}
+
+static int __on_app_startup(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       int pid = arg1;
+
+       amd_request_reply_foreach_extra(pid, __reply_foreach_cb);
+
+       return AMD_NOTI_CONTINUE;
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       int r;
+
+       LOGD("rua init");
+
+       r = amd_request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               LOGE("Failed to register cmds");
+               return -1;
+       }
+
+       r = amd_cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (r < 0) {
+               LOGE("Failed to register checkers");
+               return -1;
+       }
+
+       if (access(PATH_RUN_E_IMG, F_OK) == 0) {
+               __img_wd = amd_inotify_add_watch(PATH_RUN_E_IMG, IN_CREATE,
+                               __img_monitor_cb, NULL);
+               if (__img_wd < 0)
+                       return -1;
+
+               __find_imgs();
+       } else {
+               __dir_wd = amd_inotify_add_watch(PATH_RUN, IN_CREATE,
+                               __dir_monitor_cb, NULL);
+               if (__dir_wd < 0)
+                       return -1;
+       }
+
+       __rua_tbl = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                       NULL, __destroy_rua_info);
+       if (__rua_tbl == NULL) {
+               LOGE("Failed to create rua table");
+               return -1;
+       }
+
+       amd_noti_listen("request.user_init", __on_user_init);
+       amd_noti_listen("login_monitor.user_logout", __on_user_logout);
+       amd_noti_listen("launch.app_start.hook", __on_app_start);
+       amd_noti_listen("launch.app_startup_signal.end", __on_app_startup);
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       LOGD("rua finish");
+
+       if (__rua_tbl) {
+               g_hash_table_destroy(__rua_tbl);
+               __rua_tbl = NULL;
+       }
+
+       if (__dir_wd > 0)
+               amd_inotify_rm_watch(__dir_wd);
+       if (__img_wd > 0)
+               amd_inotify_rm_watch(__img_wd);
+}
diff --git a/modules/share/CMakeLists.txt b/modules/share/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a0abf3a
--- /dev/null
@@ -0,0 +1,45 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_SHARE "amd-mod-share")
+SET(AMD_MOD_SHARE_DIR ${CMAKE_SOURCE_DIR}/modules/share)
+PROJECT(${AMD_MOD_SHARE} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_SHARE_DIR}/src AMD_MOD_SHARE_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_SHARE_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       aul
+       bundle
+       libtzplatform-config
+       security-manager
+       )
+
+pkg_check_modules(amd_mod_share_pkgs REQUIRED ${AMD_MOD_SHARE_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_share_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_SHARE_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_SHARE} ${AMD_MOD_SHARE_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_SHARE} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_SHARE} ${amd_mod_share_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_SHARE} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/share/inc/amd_share.h b/modules/share/inc/amd_share.h
new file mode 100644 (file)
index 0000000..ae244b5
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_SHARE"
+
+#undef EXPORT
+#define EXPORT __attribute__ ((visibility("default")))
+
diff --git a/modules/share/src/amd_share.c b/modules/share/src/amd_share.c
new file mode 100644 (file)
index 0000000..750b132
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <linux/limits.h>
+
+#include <glib.h>
+#include <aul.h>
+#include <aul_svc.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <tzplatform_config.h>
+#include <security-manager.h>
+
+#include "amd.h"
+#include "amd_share.h"
+
+#define LEGACY_APP_PATH "/opt/usr/apps/"
+#define AUL_SVC_K_URI       "__APP_SVC_URI__"
+
+typedef struct _shared_info_t {
+       char *owner_appid;
+       private_sharing_req *handle;
+} shared_info_t;
+
+struct shared_info_main_s {
+       char *appid;
+       uid_t uid;
+       shared_info_t *shared_info;
+};
+
+typedef struct shared_info_main_s *shared_info_h;
+
+static shared_info_h __cur_shared_info;
+static int __temporary_permission_destroy(shared_info_h handle);
+
+static int __can_share(const char *path, const char *pkgid, uid_t uid)
+{
+       struct stat path_stat;
+       char buf[PATH_MAX];
+
+       if (stat(path, &path_stat) != 0) {
+               LOGE("failed to stat file to share (%s, %d)", path, errno);
+               return -1;
+       }
+
+       if (!S_ISREG(path_stat.st_mode)) {
+               LOGE("file is not a regular file (%s)", path);
+               return -1;
+       }
+
+       tzplatform_set_user(uid);
+       snprintf(buf, sizeof(buf), "%s/%s/data/",
+                       tzplatform_getenv(TZ_USER_APP), pkgid);
+       tzplatform_reset_user();
+
+       if (strncmp(path, buf, strlen(buf)) != 0) {
+               SECURE_LOGD("file is not in app's data directory (%s)", path);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __get_owner_pid(int caller_pid, bundle *kb)
+{
+       char *org_caller = NULL;
+       const char *appid;
+       int org_caller_pid;
+       amd_app_status_h app_status;
+       int ret;
+
+       ret = bundle_get_str(kb, AUL_K_ORG_CALLER_PID, &org_caller);
+       if (ret != BUNDLE_ERROR_NONE)
+               return caller_pid;
+
+       org_caller_pid = atoi(org_caller);
+       app_status = amd_app_status_find_by_pid(caller_pid);
+       appid = amd_app_status_get_appid(app_status);
+       if (appid && (strcmp(APP_SELECTOR, appid) == 0 ||
+                       strcmp(SHARE_PANEL, appid) == 0))
+               caller_pid = org_caller_pid;
+
+       return caller_pid;
+}
+
+static const char *__get_owner_appid(int caller_pid, bundle *kb)
+{
+       const char *owner_appid;
+       int owner_pid = -1;
+       amd_app_status_h app_status;
+
+       owner_pid = __get_owner_pid(caller_pid, kb);
+       owner_pid = getpgid(owner_pid); /* for webapp */
+       app_status = amd_app_status_find_by_pid(owner_pid);
+       owner_appid = amd_app_status_get_appid(app_status);
+
+       return owner_appid;
+}
+
+static shared_info_h __new_shared_info_handle(const char *appid, uid_t uid,
+               const char *owner_appid)
+{
+       shared_info_h h;
+       int ret;
+
+       h = malloc(sizeof(struct shared_info_main_s));
+       if (h == NULL) {
+               LOGE("Out of memory");
+               return NULL;
+       }
+
+       h->shared_info = malloc(sizeof(shared_info_t));
+       if (h->shared_info == NULL) {
+               LOGE("Out of memory");
+               free(h);
+               return NULL;
+       }
+
+       ret = security_manager_private_sharing_req_new(&h->shared_info->handle);
+       if (ret != SECURITY_MANAGER_SUCCESS) {
+               LOGE("Failed to create private sharing request handle");
+               free(h->shared_info);
+               free(h);
+               return NULL;
+       }
+
+       h->shared_info->owner_appid = strdup(owner_appid);
+       if (h->shared_info->owner_appid == NULL) {
+               LOGE("Out of memory");
+               security_manager_private_sharing_req_free(
+                               h->shared_info->handle);
+               free(h->shared_info);
+               free(h);
+               return NULL;
+       }
+
+       h->appid = strdup(appid);
+       if (h->appid == NULL) {
+               LOGE("Out of memory");
+               free(h->shared_info->owner_appid);
+               security_manager_private_sharing_req_free(
+                               h->shared_info->handle);
+               free(h->shared_info);
+               free(h);
+               return NULL;
+       }
+       h->uid = uid;
+
+       return h;
+}
+
+static char *__convert_legacy_path(const char *path, uid_t uid)
+{
+       char buf[PATH_MAX];
+       int len = strlen(LEGACY_APP_PATH);
+
+       if (strncmp(LEGACY_APP_PATH, path, len) == 0) {
+               tzplatform_set_user(uid);
+               snprintf(buf, sizeof(buf), "%s/%s",
+                       tzplatform_getenv(TZ_USER_APP), &path[len]);
+               tzplatform_reset_user();
+
+               return strdup(buf);
+       }
+
+       return strdup(path);
+}
+
+static GList *__add_valid_uri(GList *paths, int caller_pid, const char *appid,
+               const char *owner_appid, bundle *kb, uid_t uid)
+{
+       char *path = NULL;
+       const char *pkgid;
+       amd_appinfo_h ai;
+       int ret;
+
+       ret = bundle_get_str(kb, AUL_SVC_K_URI, &path);
+       if (ret != BUNDLE_ERROR_NONE)
+               return paths;
+
+       if (!path) {
+               LOGD("path was null");
+               return paths;
+       }
+
+       if (strncmp(path, "file://", 7) == 0) {
+               path = &path[7];
+       } else {
+               LOGE("file wasn't started with file://");
+               return paths;
+       }
+
+       ai = amd_appinfo_find(uid, owner_appid);
+       pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+
+       path = __convert_legacy_path(path, uid);
+       if (__can_share(path, pkgid, uid) != 0) {
+               LOGE("__can_share() returned an error");
+               free(path);
+               return paths;
+       }
+       paths = g_list_append(paths, path);
+
+       return paths;
+}
+
+static GList *__add_valid_key_for_data_selected(GList *paths, int caller_pid,
+               const char *appid, const char *owner_appid, bundle *kb,
+               uid_t uid)
+{
+       int i;
+       int len = 0;
+       const char **path_array = NULL;
+       char *path_str;
+       int type = bundle_get_type(kb, AUL_SVC_DATA_SELECTED);
+       const char *pkgid = NULL;
+       amd_appinfo_h ai = NULL;
+
+       if (type != BUNDLE_TYPE_STR_ARRAY)
+               return paths;
+
+       path_array = bundle_get_str_array(kb, AUL_SVC_DATA_SELECTED, &len);
+       if (!path_array || len <= 0) {
+               LOGE("path_array was null");
+               return paths;
+       }
+
+       ai = amd_appinfo_find(uid, owner_appid);
+       if (ai == NULL) {
+               LOGE("appinfo is NULL");
+               return paths;
+       }
+       pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+       if (pkgid == NULL) {
+               LOGE("pkgid was null");
+               return paths;
+       }
+
+       for (i = 0; i < len; i++) {
+               path_str = __convert_legacy_path(path_array[i], uid);
+               if (__can_share(path_str, pkgid, uid) == 0)
+                       paths = g_list_append(paths, path_str);
+               else
+                       free(path_str);
+       }
+
+       return paths;
+}
+
+static GList *__add_valid_key_for_data_path(GList *paths, int caller_pid,
+               const char *appid, const char *owner_appid, bundle *kb,
+               uid_t uid)
+{
+       int type = bundle_get_type(kb, AUL_SVC_DATA_PATH);
+       char *path = NULL;
+       const char **path_array = NULL;
+       int len;
+       int i;
+       const char *pkgid = NULL;
+       amd_appinfo_h ai = NULL;
+       char *path_str;
+
+       switch (type) {
+       case BUNDLE_TYPE_STR:
+               bundle_get_str(kb, AUL_SVC_DATA_PATH, &path);
+               if (!path) {
+                       LOGE("path was null");
+                       break;
+               }
+
+               ai = amd_appinfo_find(uid, owner_appid);
+               pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+               if (pkgid == NULL) {
+                       LOGE("pkgid was null");
+                       break;
+               }
+
+               path = __convert_legacy_path(path, uid);
+               if (__can_share(path, pkgid, uid) != 0) {
+                       LOGE("__can_share() returned an error");
+                       free(path);
+                       break;
+               }
+
+               paths = g_list_append(paths, path);
+               break;
+       case BUNDLE_TYPE_STR_ARRAY:
+               path_array = bundle_get_str_array(kb, AUL_SVC_DATA_PATH, &len);
+               if (!path_array || len <= 0) {
+                       LOGE("path_array was null");
+                       break;
+               }
+
+               ai = amd_appinfo_find(uid, owner_appid);
+               pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+               if (pkgid == NULL) {
+                       LOGE("pkgid was null");
+                       break;
+               }
+
+               for (i = 0; i < len; i++) {
+                       path_str = __convert_legacy_path(path_array[i], uid);
+                       if (__can_share(path_str, pkgid, uid) == 0)
+                               paths = g_list_append(paths, path_str);
+                       else
+                               free(path_str);
+               }
+
+               break;
+       }
+
+       return paths;
+}
+
+static char **__convert_list_to_array(GList *list)
+{
+       int len;
+       int i = 0;
+       char **array;
+
+       if (list == NULL)
+               return NULL;
+
+       len = g_list_length(list);
+       if (len == 0)
+               return NULL;
+
+       array = (char **)g_malloc0(sizeof(char *) * (len + 1));
+       if (array == NULL) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       while (list) {
+               array[i] = g_strdup(list->data);
+               if (array[i] == NULL) {
+                       LOGE("Out of memory");
+                       g_strfreev(array);
+                       return NULL;
+               }
+
+               list = g_list_next(list);
+               i++;
+       }
+       array[len] = NULL;
+
+       return array;
+}
+
+static int __destroy_status(amd_app_status_h status)
+{
+       GList *list;
+       GList *i;
+       shared_info_t *shared_info;
+
+       if (!status)
+               return -1;
+
+       list = amd_app_status_get_extra(status, "share");
+       if (!list)
+               return -1;
+
+       i = list;
+       while (i) {
+               shared_info = (shared_info_t *)i->data;
+               if (shared_info) {
+                       if (shared_info->owner_appid)
+                               free(shared_info->owner_appid);
+                       free(shared_info);
+               }
+               i = g_list_next(i);
+       }
+
+       g_list_free(list);
+       amd_app_status_remove_extra(status, "share");
+
+       return 0;
+}
+
+static shared_info_h __temporary_permission_create(int caller_pid, const char *appid,
+               bundle *kb, uid_t uid)
+{
+       char **path_array = NULL;
+       int len;
+       const char *owner_appid = NULL;
+       GList *paths = NULL;
+       shared_info_h h = NULL;
+       int r;
+
+       owner_appid = __get_owner_appid(caller_pid, kb);
+       paths = __add_valid_key_for_data_path(paths, caller_pid, appid,
+                       owner_appid, kb, uid);
+       paths = __add_valid_key_for_data_selected(paths, caller_pid, appid,
+                       owner_appid, kb, uid);
+       paths = __add_valid_uri(paths, caller_pid, appid, owner_appid, kb, uid);
+       if (!paths || !owner_appid)
+               goto clear;
+
+       LOGD("grant permission %s : %s", owner_appid, appid);
+
+       h = __new_shared_info_handle(appid, uid, owner_appid);
+       if (h == NULL)
+               goto clear;
+
+       len = g_list_length(paths);
+       path_array = __convert_list_to_array(paths);
+       if (path_array == NULL)
+               goto clear;
+
+       r = security_manager_private_sharing_req_set_owner_appid(
+                       h->shared_info->handle, owner_appid);
+       if (r != SECURITY_MANAGER_SUCCESS)
+               LOGE("Failed to set owner appid(%s) %d", owner_appid, r);
+
+       r = security_manager_private_sharing_req_set_target_appid(
+                       h->shared_info->handle, appid);
+       if (r != SECURITY_MANAGER_SUCCESS)
+               LOGE("Failed to set target appid(%s) %d", appid, r);
+
+       r = security_manager_private_sharing_req_add_paths(
+                       h->shared_info->handle, (const char **)path_array, len);
+       if (r != SECURITY_MANAGER_SUCCESS)
+               LOGE("Failed to add paths %d", r);
+
+       LOGD("security_manager_private_sharing_apply ++");
+       r = security_manager_private_sharing_apply(h->shared_info->handle);
+       LOGD("security_manager_private_sharing_apply --");
+       if (r != SECURITY_MANAGER_SUCCESS) {
+               LOGE("Failed to apply private sharing %d", r);
+               __temporary_permission_destroy(h);
+               h = NULL;
+       }
+
+clear:
+       if (paths)
+               g_list_free_full(paths, free);
+
+       if (path_array)
+               g_strfreev(path_array);
+
+       return h;
+}
+
+static int __temporary_permission_apply(int pid, uid_t uid, shared_info_h handle)
+{
+       amd_app_status_h status;
+       GList *list;
+
+       if (handle == NULL)
+               return -1;
+
+       status = amd_app_status_find_by_pid(pid);
+       if (status == NULL)
+               return -1;
+
+       list = amd_app_status_get_extra(status, "share");
+       list = g_list_append(list, handle->shared_info);
+       amd_app_status_set_extra(status, "share", list);
+       handle->shared_info = NULL;
+
+       return 0;
+}
+
+static int __temporary_permission_destroy(shared_info_h handle)
+{
+       int r;
+
+       if (handle == NULL)
+               return -1;
+
+       if (handle->shared_info) { /* back out */
+               LOGD("revoke permission %s : %s",
+                               handle->shared_info->owner_appid,
+                               handle->appid);
+               r = security_manager_private_sharing_drop(
+                               handle->shared_info->handle);
+               if (r != SECURITY_MANAGER_SUCCESS)
+                       LOGE("revoke error %d", r);
+
+               security_manager_private_sharing_req_free(
+                               handle->shared_info->handle);
+               free(handle->shared_info->owner_appid);
+       }
+
+       free(handle->appid);
+       free(handle);
+
+       return 0;
+}
+
+static int __temporary_permission_drop(int pid, uid_t uid)
+{
+       int r;
+       shared_info_t *sit;
+       amd_app_status_h app_status;
+       GList *list;
+
+       app_status = amd_app_status_find_by_pid(pid);
+       if (app_status == NULL)
+               return -1;
+
+       list = amd_app_status_get_extra(app_status, "share");
+       if (!list) {
+               LOGD("list was null");
+               return -1;
+       }
+
+       while (list) {
+               sit = (shared_info_t *)list->data;
+               LOGD("revoke permission %s : %d", sit->owner_appid, pid);
+               r = security_manager_private_sharing_drop(sit->handle);
+               if (r != SECURITY_MANAGER_SUCCESS)
+                       LOGE("revoke error %d", r);
+               security_manager_private_sharing_req_free(sit->handle);
+               list = g_list_next(list);
+       }
+
+       return __destroy_status(app_status);
+}
+
+static int  __on_app_result_start(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       char *appid = arg3;
+       int pid = arg1;
+       uid_t uid = arg2;
+
+       if (appid) {
+               __cur_shared_info = __temporary_permission_create(pid, appid, data, uid);
+               if (__cur_shared_info == NULL)
+                       LOGD("No sharable path : %d %s", pid, appid);
+       }
+
+       return 0;
+}
+
+static int  __on_app_result_end(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       uid_t uid = arg2;
+       int res = GPOINTER_TO_INT(arg3);
+       int ret;
+
+       if (__cur_shared_info) {
+               if (res >= 0) {
+                       ret = __temporary_permission_apply(pid, uid, __cur_shared_info);
+                       if (ret != 0) {
+                               LOGD("Couldn't apply temporary permission: %d",
+                                               ret);
+                       }
+               }
+               __temporary_permission_destroy(__cur_shared_info);
+               __cur_shared_info = NULL;
+       }
+
+       return 0;
+}
+
+static int __on_launch_prepare_end(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int caller_pid = arg1;
+       uid_t target_uid = arg2;
+       const char *appid;
+       amd_appinfo_h ai = arg3;
+       amd_app_status_h status;
+       const char *caller_appid;
+
+       appid = amd_appinfo_get_value(ai, AMD_AIT_NAME);
+       status = amd_app_status_find_by_pid(caller_pid);
+       caller_appid = amd_app_status_get_appid(status);
+
+       if (caller_appid) {
+               __cur_shared_info = __temporary_permission_create(caller_pid,
+                               appid, data, target_uid);
+               if (__cur_shared_info == NULL)
+                       LOGW("No sharable path: %d %s", caller_pid, appid);
+       }
+
+       return 0;
+}
+
+static int __on_launch_complete_end(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       uid_t target_uid = arg2;
+       int ret;
+
+       if (__cur_shared_info) {
+               ret = __temporary_permission_apply(pid, target_uid,
+                               __cur_shared_info);
+               if (ret < 0)
+                       LOGD("Couldn't apply temporary permission: %d", ret);
+
+               __temporary_permission_destroy(__cur_shared_info);
+               __cur_shared_info = NULL;
+       }
+
+       return 0;
+}
+
+static int __on_launch_cancel(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       if (__cur_shared_info) {
+               __temporary_permission_destroy(__cur_shared_info);
+               __cur_shared_info = NULL;
+       }
+
+       return 0;
+}
+
+static int __on_app_status_destroy(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_app_status_h status = arg3;
+
+       return __destroy_status(status);
+}
+
+static int __on_app_status_cleanup(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       uid_t uid = arg2;
+
+       __temporary_permission_drop(pid, uid);
+
+       return 0;
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       LOGD("share init");
+       amd_noti_listen("launch.app_result.start", __on_app_result_start);
+       amd_noti_listen("launch.app_result.end", __on_app_result_end);
+       amd_noti_listen("launch.prepare.end", __on_launch_prepare_end);
+       amd_noti_listen("launch.complete.end", __on_launch_complete_end);
+       amd_noti_listen("launch.do_starting_app.cancel", __on_launch_cancel);
+       amd_noti_listen("launch.do_starting_app.relaunch.cancel", __on_launch_cancel);
+       amd_noti_listen("app_status.cleanup", __on_app_status_cleanup);
+       amd_noti_listen("app_group.do_recycle.end", __on_app_status_cleanup);
+       amd_noti_listen("app_status.destroy", __on_app_status_destroy);
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       LOGD("share finish");
+}
+
diff --git a/modules/splash-screen/CMakeLists.txt b/modules/splash-screen/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bc2eee5
--- /dev/null
@@ -0,0 +1,49 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_SPLASH_SCREEN "amd-mod-splash-screen")
+SET(AMD_MOD_SPLASH_SCREEN_DIR ${CMAKE_SOURCE_DIR}/modules/splash-screen)
+PROJECT(${AMD_MOD_SPLASH_SCREEN} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_SPLASH_SCREEN_DIR}/src AMD_MOD_SPLASH_SCREEN_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_SPLASH_SCREEN_PKG_CHECK_MODULES
+       aul
+       dlog
+       bundle
+       sensor
+       glib-2.0
+       gio-2.0
+       wayland-client
+       wayland-tbm-client
+       tizen-extension-client
+       tizen-launch-client
+       capi-system-info
+       )
+
+PKG_CHECK_MODULES(amd_mod_splash_screen_pkgs REQUIRED ${AMD_MOD_SPLASH_SCREEN_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_splash_screen_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_SPLASH_SCREEN_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_SPLASH_SCREEN} ${AMD_MOD_SPLASH_SCREEN_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_SPLASH_SCREEN} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_SPLASH_SCREEN} ${amd_mod_splash_screen_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_SPLASH_SCREEN} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/splash-screen/inc/splash-screen-private.h b/modules/splash-screen/inc/splash-screen-private.h
new file mode 100644 (file)
index 0000000..e6e5e05
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_SPLASH_SCREEN"
+
+#undef EXPORT
+#define EXPORT __attribute__ ((visibility("default")))
+
+#define FREE_AND_NULL(x)                       \
+       do {                                    \
+               if (x) {                        \
+                       free(x);                \
+                       x = NULL;               \
+               }                               \
+       } while (0)
+
diff --git a/modules/splash-screen/src/splash-screen.c b/modules/splash-screen/src/splash-screen.c
new file mode 100644 (file)
index 0000000..4b2cb44
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <glib.h>
+#include <aul.h>
+#include <aul_cmd.h>
+#include <aul_svc.h>
+#include <aul_svc_priv_key.h>
+#include <wayland-client.h>
+#include <wayland-tbm-client.h>
+#include <tizen-launch-client-protocol.h>
+#include <vconf.h>
+#include <sensor_internal.h>
+#include <system_info.h>
+#include <amd.h>
+
+#include "splash-screen-private.h"
+
+#define APP_CONTROL_OPERATION_MAIN "http://tizen.org/appcontrol/operation/main"
+#define K_FAKE_EFFECT                  "__FAKE_EFFECT__"
+#define SPLASH_SCREEN_INFO_PATH                "/usr/share/aul"
+#define TAG_SPLASH_IMAGE               "[SplashImage]"
+#define TAG_NAME                       "Name"
+#define TAG_FILE                       "File"
+#define TAG_TYPE                       "Type"
+#define TAG_ORIENTATION                        "Orientation"
+#define TAG_INDICATOR_DISPLAY          "Indicator-display"
+#define TAG_COLOR_DEPTH                        "Color-depth"
+#define TIMEOUT_INTERVAL               10000 /* 10 sec */
+
+struct splash_image_s {
+       struct tizen_launch_splash *image;
+       char *appid;
+       char *src;
+       int type;
+       int rotation;
+       int indicator;
+       int color_depth;
+       int pid;
+       char *effect_type;
+       char *theme_type;
+       guint timer;
+};
+
+struct rotation_s {
+       int handle;
+       int angle;
+       int auto_rotate;
+};
+
+struct image_info_s {
+       char *name;
+       char *file;
+       char *type;
+       char *orientation;
+       char *indicator_display;
+       char *color_depth;
+};
+
+typedef struct splash_image_s *splash_image_h;
+static struct wl_display *display;
+static struct tizen_launch_effect *tz_launch_effect;
+static int splash_screen_initialized;
+static struct rotation_s rotation;
+static int rotation_initialized;
+static GList *default_image_list;
+static splash_image_h splash_image;
+static splash_image_h cur_splash_image;
+
+static int __init_splash_screen(void);
+static int __init_rotation(void);
+
+static splash_image_h __splash_screen_get_image(int pid)
+{
+       if (splash_image == NULL)
+               return NULL;
+
+       if (splash_image->pid == pid)
+               return splash_image;
+
+       return NULL;
+}
+
+static void __set_splash_image(splash_image_h si)
+{
+       splash_image = si;
+}
+
+static void __splash_screen_destroy_image(splash_image_h si)
+{
+       if (si == NULL)
+               return;
+
+       if (si->timer)
+               g_source_remove(si->timer);
+       if (si->theme_type)
+               free(si->theme_type);
+       if (si->effect_type)
+               free(si->effect_type);
+       if (si->appid)
+               free(si->appid);
+       if (si->src)
+               free(si->src);
+       if (si->image) {
+               tizen_launch_splash_destroy(si->image);
+               wl_display_flush(display);
+       }
+       free(si);
+       __set_splash_image(NULL);
+}
+
+static gboolean __timeout_handler(gpointer data)
+{
+       splash_image_h si = (splash_image_h)data;
+       amd_app_status_h app_status;
+
+       if (si == NULL)
+               return FALSE;
+
+       app_status = amd_app_status_find_by_pid(si->pid);
+       if (app_status) {
+               if (amd_app_status_is_starting(app_status) == false) {
+                       LOGW("% is not starting", si->pid);
+                       return TRUE;
+               }
+       }
+
+       si->timer = 0;
+       __splash_screen_destroy_image(si);
+
+       return FALSE;
+}
+
+static int __app_can_launch_splash_image(amd_appinfo_h ai, bundle *kb)
+{
+       const char *comp_type;
+       const char *fake_effect;
+       int display;
+
+       comp_type = amd_appinfo_get_value(ai, AMD_AIT_COMPTYPE);
+       if (comp_type == NULL || strcmp(comp_type, APP_TYPE_UI) != 0) {
+               LOGD("component_type: %s", comp_type);
+               return -1;
+       }
+
+       fake_effect = bundle_get_val(kb, K_FAKE_EFFECT);
+       if (fake_effect && !strcmp(fake_effect, "OFF"))
+               return -1;
+
+       amd_appinfo_get_int_value(ai, AMD_AIT_SPLASH_SCREEN_DISPLAY, &display);
+       if (!(display & APP_ENABLEMENT_MASK_ACTIVE))
+               return -1;
+
+       return 0;
+}
+
+static struct appinfo_splash_image *__get_splash_image_info(
+               amd_appinfo_h ai, bundle *kb, int cmd)
+{
+       amd_appinfo_h caller_ai;
+       amd_appinfo_splash_image_h image;
+       const char *operation;
+       const char *uid_str;
+       const char *caller_appid;
+       const char *comp_type;
+       uid_t uid = 0;
+       bool landscape;
+
+       if ((rotation.angle == 90 || rotation.angle == 270)
+                               && rotation.auto_rotate == true)
+               landscape = true;
+       else
+               landscape = false;
+
+       operation = bundle_get_val(kb, AUL_SVC_K_OPERATION);
+       if (cmd == APP_OPEN || (operation &&
+                       (!strcmp(operation, APP_CONTROL_OPERATION_MAIN) ||
+                        !strcmp(operation, AUL_SVC_OPERATION_DEFAULT)))) {
+               return amd_appinfo_find_splash_image(ai, "launch-effect",
+                               landscape);
+       }
+
+       if (operation) {
+               image = amd_appinfo_find_splash_image(ai, operation, landscape);
+               if (image)
+                       return image;
+       }
+
+       caller_appid = bundle_get_val(kb, AUL_K_CALLER_APPID);
+       if (caller_appid == NULL)
+               return NULL;
+
+       uid_str = bundle_get_val(kb, AUL_K_TARGET_UID);
+       if (uid_str == NULL)
+               return NULL;
+
+       if (isdigit(*uid_str))
+               uid = atol(uid_str);
+       caller_ai = amd_appinfo_find(uid, caller_appid);
+       if (caller_ai == NULL)
+               return NULL;
+
+       comp_type = amd_appinfo_get_value(caller_ai, AMD_AIT_COMPTYPE);
+       if (comp_type == NULL)
+               return NULL;
+
+       if (!strcmp(comp_type, APP_TYPE_WATCH) ||
+                       !strcmp(comp_type, APP_TYPE_WIDGET)) {
+               return amd_appinfo_find_splash_image(ai, "launch-effect",
+                               landscape);
+       }
+
+       return NULL;
+}
+
+static struct image_info_s *__get_default_image_info(bundle *kb)
+{
+       struct image_info_s *info = NULL;
+       const char *orientation = "portrait";
+       const char *str;
+       GList *list;
+
+       if (default_image_list == NULL)
+               return NULL;
+
+       if ((rotation.angle == 90 || rotation.angle == 270) &&
+                       rotation.auto_rotate == true)
+               orientation = "landscape";
+
+       str = bundle_get_val(kb, AUL_SVC_K_SPLASH_SCREEN);
+       if (str == NULL)
+               str = "default";
+
+       list = default_image_list;
+       while (list) {
+               info = (struct image_info_s *)list->data;
+               if (info && strcmp(str, info->name) == 0) {
+                       if (!strcasecmp(info->orientation, orientation))
+                               return info;
+               }
+
+               list = g_list_next(list);
+       }
+
+       return NULL;
+}
+
+static splash_image_h __splash_screen_create_image(amd_appinfo_h ai,
+               bundle *kb, int cmd, bool is_subapp)
+{
+       amd_appinfo_splash_image_h image_info;
+       struct splash_image_s *si;
+       struct image_info_s *info;
+       const char *appid;
+       const char *src = NULL;
+       const char *type;
+       int file_type = 0;
+       int indicator = 1;
+       int color_depth = 24; /* default */
+
+       if (!splash_screen_initialized) {
+               if (__init_splash_screen() < 0)
+                       return NULL;
+       }
+
+       if (__app_can_launch_splash_image(ai, kb) < 0)
+               return NULL;
+
+       if (!rotation_initialized) {
+               if (__init_rotation() < 0)
+                       LOGW("Failed to initialize rotation");
+       }
+       LOGD("angle: %d", rotation.angle);
+
+       image_info = __get_splash_image_info(ai, kb, cmd);
+       if (image_info) {
+               src = amd_appinfo_splash_image_get_source(image_info);
+               if (access(src, F_OK) != 0)
+                       return NULL;
+               type = amd_appinfo_splash_image_get_type(image_info);
+               if (type && strcasecmp(type, "edj") == 0)
+                       file_type = 1;
+               indicator = amd_appinfo_splash_image_get_indicator_display(
+                               image_info);;
+               color_depth = amd_appinfo_splash_image_get_color_depth(
+                               image_info);
+       } else {
+               info = __get_default_image_info(kb);
+               if (info == NULL)
+                       return NULL;
+               src = info->file;
+               if (access(src, F_OK) != 0)
+                       return NULL;
+               if (strcasecmp(info->type, "edj") == 0)
+                       file_type = 1;
+               if (strcmp(info->indicator_display, "false") == 0)
+                       indicator = 0;
+               if (strcmp(info->color_depth, "32") == 0)
+                       color_depth = 32;
+       }
+
+       si = (struct splash_image_s *)calloc(1, sizeof(struct splash_image_s));
+       if (si == NULL) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       si->image = tizen_launch_effect_create_splash_img(
+                       tz_launch_effect);
+       if (si->image == NULL) {
+               LOGE("Failed to get launch image");
+               free(si);
+               return NULL;
+       }
+       wl_display_flush(display);
+
+       si->src = strdup(src);
+       if (si->src == NULL) {
+               LOGE("out of memory");
+               __splash_screen_destroy_image(si);
+               return NULL;
+       }
+
+       if (is_subapp)
+               si->effect_type = strdup("depth-in");
+       else
+               si->effect_type = strdup("launch");
+       if (si->effect_type == NULL) {
+               LOGE("Out of memory");
+               __splash_screen_destroy_image(si);
+               return NULL;
+       }
+
+       si->theme_type = strdup("default");
+       if (si->theme_type == NULL) {
+               LOGE("Out of memory");
+               __splash_screen_destroy_image(si);
+               return NULL;
+       }
+
+       appid = amd_appinfo_get_value(ai, AMD_AIT_NAME);
+       si->appid = strdup(appid);
+       if (si->appid == NULL) {
+               LOGE("out of memory");
+               __splash_screen_destroy_image(si);
+               return NULL;
+       }
+
+       si->type = file_type;
+       si->rotation = rotation.angle;
+       si->indicator = indicator;
+       si->color_depth = color_depth;
+
+       si->timer = g_timeout_add(TIMEOUT_INTERVAL, __timeout_handler, si);
+       __set_splash_image(si);
+
+       return si;
+}
+
+static void __splash_screen_send_image(splash_image_h si)
+{
+       struct wl_array options;
+       bundle *b;
+       bundle_raw *raw_data = NULL;
+       int len = 0;
+       int ret;
+       size_t size;
+       void *data;
+
+       if (si == NULL || si->image == NULL)
+               return;
+
+       wl_array_init(&options);
+
+       b = bundle_create();
+       if (b == NULL) {
+               LOGE("out of memory");
+               return;
+       }
+
+       bundle_add(b, AUL_K_APPID, si->appid);
+       ret = bundle_encode(b, &raw_data, &len);
+       if (ret != BUNDLE_ERROR_NONE) {
+               LOGE("Failed to encode bundle");
+               bundle_free(b);
+               return;
+       }
+       bundle_free(b);
+
+       size = strlen((const char *)raw_data);
+       data = wl_array_add(&options, size + 1);
+       memcpy(data, raw_data, size + 1);
+       free(raw_data);
+
+       LOGD("src(%s), type(%d), color-depth(%d), rotation(%d), " \
+                       "indicator(%d), effect_type(%s)",
+                       si->src, si->type, si->color_depth, si->rotation,
+                       si->indicator, si->effect_type);
+       tizen_launch_splash_launch(si->image, si->src, si->type,
+                       si->color_depth, si->rotation, si->indicator,
+                       si->effect_type, si->theme_type, &options);
+       wl_display_flush(display);
+
+       wl_array_release(&options);
+}
+
+static void __splash_screen_send_pid(splash_image_h si, int pid)
+{
+       if (si == NULL)
+               return;
+
+       LOGD("pid(%d)", pid);
+       si->pid = pid;
+       tizen_launch_splash_owner(si->image, pid);
+       wl_display_flush(display);
+}
+
+static void __splash_screen_set_effect_type(int pid, const char *appid, bool is_subapp)
+{
+       struct wl_array options;
+       bundle *b;
+       bundle_raw *raw_data = NULL;
+       int len = 0;
+       int ret;
+       size_t size;
+       void *data;
+       const char *effect_type;
+
+       if (!splash_screen_initialized)
+               return;
+
+       wl_array_init(&options);
+
+       if (is_subapp)
+               effect_type = "depth-in";
+       else
+               effect_type = "launch";
+
+       b = bundle_create();
+       if (b == NULL) {
+               LOGE("out of memory");
+               return;
+       }
+
+       bundle_add(b, AUL_K_APPID, appid);
+       ret = bundle_encode(b, &raw_data, &len);
+       if (ret != BUNDLE_ERROR_NONE) {
+               LOGE("Failed to encode bundle");
+               bundle_free(b);
+               return;
+       }
+       bundle_free(b);
+
+       size = strlen((const char *)raw_data);
+       data = wl_array_add(&options, size + 1);
+       memcpy(data, raw_data, size + 1);
+       free(raw_data);
+
+       LOGD("effect_type(%s), pid(%d)", effect_type, pid);
+       tizen_launch_effect_type_set(tz_launch_effect, effect_type,
+                       pid, &options);
+       wl_display_flush(display);
+
+       wl_array_release(&options);
+}
+
+static int __init_splash_screen(void)
+{
+       if (!display) {
+               display = amd_wayland_get_display();
+               if (!display) {
+                       LOGE("Failed to get display");
+                       return -1;
+               }
+       }
+
+       if (!tz_launch_effect) {
+               LOGE("Failed to bind tizen launch screen");
+               return -1;
+       }
+
+       splash_screen_initialized = 1;
+
+       return 0;
+}
+
+static void __rotation_changed_cb(sensor_t sensor, unsigned int event_type,
+               sensor_data_t *data, void *user_data)
+{
+       int event;
+
+       if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
+               return;
+
+       event = (int)data->values[0];
+       switch (event) {
+       case AUTO_ROTATION_DEGREE_0:
+               rotation.angle = 0;
+               break;
+       case AUTO_ROTATION_DEGREE_90:
+               rotation.angle = 90;
+               break;
+       case AUTO_ROTATION_DEGREE_180:
+               rotation.angle = 180;
+               break;
+       case AUTO_ROTATION_DEGREE_270:
+               rotation.angle = 270;
+               break;
+       default:
+               break;
+       }
+
+       LOGD("angle: %d", rotation.angle);
+}
+
+static void __auto_rotate_screen_cb(keynode_t *key, void *data)
+{
+       rotation.auto_rotate = vconf_keynode_get_bool(key);
+       if (!rotation.auto_rotate) {
+               LOGD("auto_rotate: %d, angle: %d",
+                               rotation.auto_rotate, rotation.angle);
+       }
+}
+
+static bool __is_tv_profile(void)
+{
+       char *profile = NULL;
+
+       system_info_get_platform_string("http://tizen.org/feature/profile",
+                       &profile);
+       if (!profile)
+               return false;
+
+       if (profile[0] == 't' && profile[0] == 'T')
+               return true;
+
+       return false;
+}
+
+static int __init_rotation(void)
+{
+       int ret;
+       bool r;
+       sensor_t sensor;
+
+       if (__is_tv_profile()) {
+               rotation_initialized = 1;
+               return 0;
+       }
+
+       sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
+       rotation.angle = 0;
+       rotation.handle = sensord_connect(sensor);
+       if (rotation.handle < 0) {
+               LOGW("Failed to connect sensord");
+               return -1;
+       }
+
+       r = sensord_register_event(rotation.handle,
+                       AUTO_ROTATION_CHANGE_STATE_EVENT,
+                       SENSOR_INTERVAL_NORMAL,
+                       0,
+                       __rotation_changed_cb,
+                       NULL);
+       if (!r) {
+               LOGW("Failed to register event");
+               sensord_disconnect(rotation.handle);
+               return -1;
+       }
+
+       r = sensord_start(rotation.handle, 0);
+       if (!r) {
+               LOGW("Failed to start sensord");
+               sensord_unregister_event(rotation.handle,
+                               AUTO_ROTATION_CHANGE_STATE_EVENT);
+               sensord_disconnect(rotation.handle);
+               return -1;
+       }
+
+       ret = vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL,
+                       &rotation.auto_rotate);
+       if (ret != VCONF_OK)
+               rotation.auto_rotate = false;
+
+       ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL,
+                       __auto_rotate_screen_cb, NULL);
+       if (ret != 0) {
+               LOGW("Failed to register callback for %s",
+                               VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL);
+       }
+       rotation_initialized = 1;
+
+       return 0;
+}
+
+static void __destroy_image_info(struct image_info_s *info)
+{
+       if (info == NULL)
+               return;
+
+       if (info->color_depth)
+               free(info->color_depth);
+       if (info->indicator_display)
+               free(info->indicator_display);
+       if (info->type)
+               free(info->type);
+       if (info->orientation)
+               free(info->orientation);
+       if (info->file)
+               free(info->file);
+       if (info->name)
+               free(info->name);
+       free(info);
+}
+
+struct image_info_s *__create_image_info(void)
+{
+       struct image_info_s *info;
+
+       info = (struct image_info_s *)calloc(1, sizeof(struct image_info_s));
+       if (info == NULL) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       return info;
+}
+
+static int __validate_image_info(struct image_info_s *info)
+{
+       if (!info || !info->name || !info->file || !info->orientation)
+               return -1;
+
+       if (!info->type) {
+               if (strstr(info->file, "edj"))
+                       info->type = strdup("edj");
+               else
+                       info->type = strdup("img");
+               if (info->type == NULL) {
+                       LOGE("Out of memory");
+                       return -1;
+               }
+       }
+
+       if (!info->indicator_display) {
+               info->indicator_display = strdup("true");
+               if (info->indicator_display == NULL) {
+                       LOGE("Out of memory");
+                       return -1;
+               }
+       }
+
+       if (!info->color_depth) {
+               info->color_depth = strdup("24");
+               if (info->color_depth == NULL) {
+                       LOGE("Out of memory");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static void __parse_file(const char *file)
+{
+       FILE *fp;
+       char buf[LINE_MAX];
+       char *tok1 = NULL;
+       char *tok2 = NULL;
+       struct image_info_s *info = NULL;
+
+       fp = fopen(file, "rt");
+       if (fp == NULL)
+               return;
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               FREE_AND_NULL(tok1);
+               FREE_AND_NULL(tok2);
+               sscanf(buf, "%ms %ms", &tok1, &tok2);
+
+               if (tok1 && strcasecmp(TAG_SPLASH_IMAGE, tok1) == 0) {
+                       if (info) {
+                               if (__validate_image_info(info) < 0) {
+                                       __destroy_image_info(info);
+                               } else {
+                                       default_image_list = g_list_append(
+                                                       default_image_list,
+                                                       info);
+                               }
+                       }
+                       info = __create_image_info();
+                       continue;
+               }
+
+               if (!tok1 || !tok2 || !info)
+                       continue;
+
+               if (strcasecmp(TAG_NAME, tok1) == 0)
+                       info->name = strdup(tok2);
+               else if (strcasecmp(TAG_FILE, tok1) == 0)
+                       info->file = strdup(tok2);
+               else if (strcasecmp(TAG_TYPE, tok1) == 0)
+                       info->type = strdup(tok2);
+               else if (strcasecmp(TAG_ORIENTATION, tok1) == 0)
+                       info->orientation = strdup(tok2);
+               else if (strcasecmp(TAG_INDICATOR_DISPLAY, tok1) == 0)
+                       info->indicator_display = strdup(tok2);
+               else if (strcasecmp(TAG_COLOR_DEPTH, tok1) == 0)
+                       info->color_depth = strdup(tok2);
+       }
+
+       if (info) {
+               if (__validate_image_info(info) < 0) {
+                       __destroy_image_info(info);
+               } else {
+                       default_image_list = g_list_append(default_image_list,
+                                       info);
+               }
+       }
+
+       if (tok1)
+               free(tok1);
+       if (tok2)
+               free(tok2);
+
+       fclose(fp);
+}
+
+static int __load_splash_screen_info(const char *path)
+{
+       DIR *dp;
+       struct dirent *entry = NULL;
+       char *ext;
+       char buf[PATH_MAX];
+
+       dp = opendir(path);
+       if (dp == NULL)
+               return -1;
+
+       while ((entry = readdir(dp)) != NULL) {
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               ext = strrchr(entry->d_name, '.');
+               if (ext && !strcmp(ext, ".conf")) {
+                       snprintf(buf, sizeof(buf), "%s/%s",
+                                       path, entry->d_name);
+                       __parse_file(buf);
+               }
+       }
+
+       closedir(dp);
+
+       return 0;
+}
+
+static int __on_launch_start(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       int cmd = arg1;
+       bundle *kb = data;
+       amd_launch_context_h h = arg3;
+
+       cur_splash_image = NULL;
+       if (!amd_launch_context_get_instance_id(h) &&
+                       !amd_launch_context_is_bg_launch(h)) {
+               cur_splash_image = __splash_screen_create_image(
+                               amd_launch_context_get_appinfo(h), kb, cmd,
+                               amd_launch_context_is_subapp(h));
+               __splash_screen_send_image(cur_splash_image);
+       }
+
+       return 0;
+}
+
+static int __on_launch_end(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       amd_launch_context_h h = arg3;
+       amd_appinfo_h ai = amd_launch_context_get_appinfo(h);
+       const char *comp_type;
+
+       comp_type = amd_appinfo_get_value(ai, AMD_AIT_COMPTYPE);
+       if (cur_splash_image) {
+               __splash_screen_send_pid(cur_splash_image,
+                               amd_launch_context_get_pid(h));
+       } else if (comp_type && !strcmp(comp_type, APP_TYPE_UI)) {
+               __splash_screen_set_effect_type(amd_launch_context_get_pid(h),
+                               amd_launch_context_get_appid(h),
+                               amd_launch_context_is_subapp(h));
+       }
+
+       return 0;
+}
+
+static int __on_launch_cancel(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       if (cur_splash_image) {
+               __splash_screen_destroy_image(cur_splash_image);
+               cur_splash_image = NULL;
+       }
+
+       return 0;
+}
+
+static int __on_cleanup(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       int pid = arg1;
+       splash_image_h si;
+
+       si = __splash_screen_get_image(pid);
+       if (si)
+               __splash_screen_destroy_image(si);
+
+       return 0;
+}
+
+static int __on_wl_listener(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       uint32_t id = (uint32_t)arg1;
+       struct wl_registry *registry = (struct wl_registry *)arg3;
+
+       if (!tz_launch_effect) {
+               tz_launch_effect = wl_registry_bind(registry, id,
+                               &tizen_launch_effect_interface, 1);
+               LOGD("tz_launch_effect(%p)", tz_launch_effect);
+       }
+
+       return 0;
+}
+
+static int __on_wl_listener_remove(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       if (tz_launch_effect) {
+               tizen_launch_effect_destroy(tz_launch_effect);
+               tz_launch_effect = NULL;
+       }
+
+       return 0;
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       LOGD("splash screen init");
+
+       __load_splash_screen_info(SPLASH_SCREEN_INFO_PATH);
+
+       if (__init_rotation() < 0)
+               LOGW("Failed to initialize rotation");
+
+       amd_noti_listen("wayland.listener.tizen_launch_effect",
+                       __on_wl_listener);
+       amd_noti_listen("wayland.listener_remove", __on_wl_listener_remove);
+       amd_noti_listen("launch.do_starting_app.start", __on_launch_start);
+       amd_noti_listen("launch.do_starting_app.cancel",  __on_launch_cancel);
+       amd_noti_listen("launch.do_starting_app.end", __on_launch_end);
+       amd_noti_listen("main.app_dead", __on_cleanup);
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       LOGD("splash screen finish");
+}
diff --git a/modules/ui-core/CMakeLists.txt b/modules/ui-core/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9829151
--- /dev/null
@@ -0,0 +1,47 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_UI_CORE "amd-mod-ui-core")
+SET(AMD_MOD_UI_CORE_DIR ${CMAKE_SOURCE_DIR}/modules/ui-core)
+PROJECT(${AMD_MOD_UI_CORE} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_UI_CORE_DIR}/src AMD_MOD_UI_CORE_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_UI_CORE_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       aul
+       bundle
+       wayland-client
+       tizen-extension-client
+       wayland-tbm-client
+       capi-system-info
+       )
+
+pkg_check_modules(amd_mod_ui_core_pkgs REQUIRED ${AMD_MOD_UI_CORE_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_ui_core_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_UI_CORE_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_UI_CORE} ${AMD_MOD_UI_CORE_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_UI_CORE} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_UI_CORE} ${amd_mod_ui_core_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_UI_CORE} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/ui-core/inc/amd_app_group.h b/modules/ui-core/inc/amd_app_group.h
new file mode 100644 (file)
index 0000000..cebc61e
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <glib.h>
+
+typedef GList *app_group_h;
+
+app_group_h _app_group_find(int pid);
+int _app_group_get_window(app_group_h h);
+void _app_group_get_group_pids(int leader_pid, int *cnt, int **pids);
+int _app_group_get_leader_pid(app_group_h h);
+int _app_group_init(void);
+void _app_group_fini(void);
diff --git a/modules/ui-core/inc/amd_screen_connector.h b/modules/ui-core/inc/amd_screen_connector.h
new file mode 100644 (file)
index 0000000..1f28182
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+int _screen_connector_add_app_screen(int pid, unsigned int surf,
+               const char *instance_id, uid_t uid);
+int _screen_connector_init(void);
+void _screen_connector_fini(void);
diff --git a/modules/ui-core/src/amd_app_group.c b/modules/ui-core/src/amd_app_group.c
new file mode 100644 (file)
index 0000000..38c93fb
--- /dev/null
@@ -0,0 +1,2122 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <dlog.h>
+#include <aul.h>
+#include <aul_svc.h>
+#include <bundle_internal.h>
+#include <aul_sock.h>
+#include <wayland-client.h>
+#include <wayland-tbm-client.h>
+#include <tizen-extension-client-protocol.h>
+#include <stdlib.h>
+#include <system_info.h>
+
+#include "amd.h"
+#include "amd_app_group.h"
+#include "amd_screen_connector.h"
+
+#define APP_SVC_K_LAUNCH_MODE   "__APP_SVC_LAUNCH_MODE__"
+#undef LOG_TAG
+#define LOG_TAG "AMD_APP_GROUP"
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define STATUS_FOREGROUND "fg"
+#define STATUS_BACKGROUND "bg"
+#define TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP \
+       (!(__get_tizen_profile() & (TIZEN_PROFILE_TV)))
+
+typedef enum {
+       TIZEN_PROFILE_UNKNOWN = 0,
+       TIZEN_PROFILE_MOBILE = 0x1,
+       TIZEN_PROFILE_WEARABLE = 0x2,
+       TIZEN_PROFILE_TV = 0x4,
+       TIZEN_PROFILE_IVI = 0x8,
+       TIZEN_PROFILE_COMMON = 0x10,
+} tizen_profile_t;
+
+typedef enum {
+       APP_GROUP_LAUNCH_MODE_SINGLE = 0,
+       APP_GROUP_LAUNCH_MODE_GROUP,
+       APP_GROUP_LAUNCH_MODE_CALLER,
+} app_group_launch_mode;
+
+typedef struct _app_group_context_t {
+       int pid;
+       int wid;
+       int status;
+       int caller_pid;
+       app_group_launch_mode launch_mode;
+       bool fg;
+       bool group_sig;
+       bool can_be_leader;
+       bool reroute;
+       bool can_shift;
+       bool recycle;
+} app_group_context_t;
+
+struct launch_context_s {
+       app_group_launch_mode mode;
+       bool can_attach;
+       int lpid;
+};
+
+static struct wl_display *display;
+static struct tizen_policy *tz_policy;
+static int tz_policy_initialized;
+static GHashTable *app_group_hash;
+static GList *recycle_bin;
+static struct launch_context_s __launch_context;
+
+static int __app_group_set_status(app_group_h h, int status, bool force);
+static void __app_group_clear_top(app_group_h h, uid_t uid);
+static bool __app_group_is_sub_app(app_group_h h);
+
+static int __wl_init(void)
+{
+       if (!display) {
+               display = amd_wayland_get_display();
+               if (!display) {
+                       LOGE("Failed to get display");
+                       return -1;
+               }
+       }
+
+       if (!tz_policy)
+               return -1;
+
+       tz_policy_initialized = 1;
+
+       return 0;
+}
+
+static void __lower_window(int wid)
+{
+       if (!tz_policy_initialized) {
+               if (__wl_init() < 0) {
+                       LOGE("__wl_init() failed");
+                       return;
+               }
+       }
+
+       tizen_policy_lower_by_res_id(tz_policy, wid);
+       wl_display_roundtrip(display);
+}
+
+static void __attach_window(int parent_wid, int child_wid)
+{
+       if (!tz_policy_initialized) {
+               if (__wl_init() < 0) {
+                       LOGE("__wl_init() failed");
+                       return;
+               }
+       }
+
+       tizen_policy_set_transient_for(tz_policy, child_wid, parent_wid);
+       wl_display_roundtrip(display);
+}
+
+static void __detach_window(int child_wid)
+{
+       if (!tz_policy_initialized) {
+               if (__wl_init() < 0) {
+                       LOGE("__wl_init() failed");
+                       return;
+               }
+       }
+
+       tizen_policy_unset_transient_for(tz_policy, child_wid);
+       wl_display_roundtrip(display);
+}
+
+static void __activate_below(int wid, int below_wid)
+{
+       if (!tz_policy_initialized) {
+               if (__wl_init() < 0) {
+                       LOGE("__wl_init() failed");
+                       return;
+               }
+       }
+
+       tizen_policy_activate_below_by_res_id(tz_policy, below_wid, wid);
+       wl_display_roundtrip(display);
+}
+
+static void __activate_above(int wid, int above_wid)
+{
+       if (!tz_policy_initialized) {
+               if (__wl_init() < 0) {
+                       LOGE("__wl_init() failed");
+                       return;
+               }
+       }
+
+       tizen_policy_activate_above_by_res_id(tz_policy, above_wid, wid);
+       wl_display_roundtrip(display);
+}
+
+static gint __comp_pid(gconstpointer a, gconstpointer b)
+{
+       app_group_context_t *ac1 = (app_group_context_t *)a;
+
+       return ac1->pid - GPOINTER_TO_INT(b);
+}
+
+static void __list_destroy_cb(gpointer data)
+{
+       free(data);
+}
+
+static GList *__get_context_node(int pid)
+{
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       GList *list;
+       GList *i;
+       app_group_context_t *ac;
+
+       g_hash_table_iter_init(&iter, app_group_hash);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               list = (GList *)value;
+               i = g_list_first(list);
+               while (i != NULL) {
+                       ac = (app_group_context_t *)i->data;
+                       if (ac && ac->pid == pid)
+                               return i;
+
+                       i = g_list_next(i);
+               }
+       }
+
+       return NULL;
+}
+
+app_group_h _app_group_find(int pid)
+{
+       GList *node = __get_context_node(pid);
+
+       if (!node)
+               node = __get_context_node(getpgid(pid));
+
+       return node;
+}
+
+static bool __app_group_is_leader(app_group_h h)
+{
+       if (!h)
+               return false;
+
+       if (g_list_first(h) == h)
+               return true;
+
+       return false;
+}
+
+static gboolean __hash_table_cb(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       int pid = GPOINTER_TO_INT(user_data);
+       GList *list = (GList *)value;
+       GList *itr = g_list_first(list);
+       app_group_context_t *ac;
+
+       while (itr != NULL) {
+               ac = (app_group_context_t *)itr->data;
+               if (ac && ac->pid == pid) {
+                       free(ac);
+                       list = g_list_delete_link(list, itr);
+                       if (g_list_length(list) == 0) {
+                               g_list_free_full(list, __list_destroy_cb);
+                               return TRUE;
+                       } else {
+                               return FALSE;
+                       }
+               }
+               itr = g_list_next(itr);
+       }
+
+       return FALSE;
+}
+
+static void __prepare_to_suspend_services(int pid, uid_t uid)
+{
+       int ret;
+       int dummy = 0;
+
+       LOGD("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+       ret = aul_sock_send_raw(pid, uid, APP_SUSPEND, (unsigned char *)&dummy,
+                       sizeof(int), AUL_SOCK_NOREPLY);
+       if (ret < 0)
+               LOGE("error on suspend service for pid: %d", pid);
+}
+
+static void __prepare_to_wake_services(int pid, uid_t uid)
+{
+       int ret;
+       int dummy = 0;
+
+       LOGD("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+       ret = aul_sock_send_raw(pid, uid, APP_WAKE, (unsigned char *)&dummy,
+                       sizeof(int), AUL_SOCK_NOREPLY);
+       if (ret < 0)
+               LOGE("error on wake service for pid: %d", pid);
+}
+
+static void __set_flag(GList *list, int cpid, int flag, bool force)
+{
+       app_group_context_t *ac;
+       amd_app_status_h app_status;
+       amd_appinfo_h ai;
+       const char *appid;
+       const char *pkgid;
+       bool bg_allowed;
+       uid_t uid;
+
+       while (list) {
+               ac = (app_group_context_t *)list->data;
+               if (ac && (ac->fg != flag || force)) {
+                       app_status = amd_app_status_find_by_pid(ac->pid);
+                       appid = amd_app_status_get_appid(app_status);
+                       uid = amd_app_status_get_uid(app_status);
+                       ai = amd_appinfo_find(uid, appid);
+                       pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+                       bg_allowed = amd_suspend_is_allowed_background(ai);
+                       if (flag) {
+                               LOGD("Send FG signal %s", appid);
+                               aul_send_app_status_change_signal(ac->pid,
+                                               appid, pkgid, STATUS_FOREGROUND,
+                                               APP_TYPE_UI);
+                               if (!bg_allowed) {
+                                       amd_app_status_find_service_apps(
+                                               app_status,
+                                               STATUS_VISIBLE,
+                                               __prepare_to_wake_services,
+                                               false);
+                               }
+                       } else {
+                               LOGD("send BG signal %s", appid);
+                               aul_send_app_status_change_signal(ac->pid,
+                                               appid, pkgid, STATUS_BACKGROUND,
+                                               APP_TYPE_UI);
+                               if (!bg_allowed) {
+                                       amd_app_status_find_service_apps(
+                                               app_status,
+                                               STATUS_BG,
+                                               __prepare_to_suspend_services,
+                                               true);
+                                       if (force && cpid == ac->pid) {
+                                               __prepare_to_suspend_services(
+                                                               ac->pid, uid);
+                                               amd_suspend_add_timer(ac->pid);
+                                       }
+                               }
+                       }
+                       ac->fg = flag;
+               }
+               list = g_list_next(list);
+       }
+}
+
+static void __set_fg_flag(int cpid, int flag, bool force)
+{
+       int lpid = _app_group_get_leader_pid(_app_group_find(cpid));
+       GList *i = __get_context_node(lpid);
+
+       if (!i)
+               return;
+
+       __set_flag(i, cpid, flag, force);
+}
+
+static bool __is_visible(int cpid)
+{
+       int lpid = _app_group_get_leader_pid(_app_group_find(cpid));
+       GList *i = __get_context_node(lpid);
+       app_group_context_t *ac;
+
+       if (!i)
+               return false;
+
+       i = g_list_first(i);
+       while (i) {
+               ac = (app_group_context_t *)i->data;
+               if (ac && ac->status == STATUS_VISIBLE)
+                       return true;
+
+               i = g_list_next(i);
+       }
+
+       return false;
+}
+
+static bool __can_attach_window(bundle *b, const char *appid,
+               app_group_launch_mode *launch_mode, uid_t uid)
+{
+       const char *str;
+       const char *mode;
+       amd_appinfo_h ai;
+
+       ai = amd_appinfo_find(uid, appid);
+       mode = amd_appinfo_get_value(ai, AMD_AIT_LAUNCH_MODE);
+       if (mode == NULL)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLE;
+       else if (strcmp(mode, "caller") == 0)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_CALLER;
+       else if (strcmp(mode, "single") == 0)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLE;
+       else if (strcmp(mode, "group") == 0)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_GROUP;
+
+       switch (*launch_mode) {
+       case APP_GROUP_LAUNCH_MODE_CALLER:
+               LOGD("launch mode from db is caller");
+               str = bundle_get_val(b, APP_SVC_K_LAUNCH_MODE);
+               if (str != NULL && strncmp(str, "group", 5) == 0)
+                       return true;
+               break;
+       case APP_GROUP_LAUNCH_MODE_GROUP:
+               return true;
+       case APP_GROUP_LAUNCH_MODE_SINGLE:
+               return false;
+       }
+
+       return false;
+}
+
+static bool __can_be_leader(bundle *b)
+{
+       const char *str;
+
+       str = bundle_get_val(b, AUL_SVC_K_CAN_BE_LEADER);
+       if (str != NULL && strcmp(str, "true") == 0)
+               return true;
+
+       return false;
+}
+
+static int __get_caller_pid(bundle *kb)
+{
+       const char *pid_str;
+       int pid;
+
+       pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
+       if (pid_str)
+               goto end;
+
+       pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
+       if (pid_str == NULL)
+               return -1;
+
+end:
+       pid = atoi(pid_str);
+       if (pid <= 1)
+               return -1;
+
+       return pid;
+}
+
+static app_group_context_t *__detach_context_from_recycle_bin(int pid)
+{
+       GList *iter = recycle_bin;
+       app_group_context_t *ac;
+
+       while (iter) {
+               ac = (app_group_context_t *)iter->data;
+               if (ac && ac->pid == pid) {
+                       recycle_bin = g_list_delete_link(recycle_bin, iter);
+                       return ac;
+               }
+
+               iter = g_list_next(iter);
+       }
+
+       return NULL;
+}
+
+static int __app_group_get_pid(app_group_h h)
+{
+       app_group_context_t *context;
+
+       if (!h)
+               return -1;
+
+       context = h->data;
+
+       return context->pid;
+}
+
+static void __group_remove(app_group_h h)
+{
+       GList *prev = g_list_previous(h);
+       int pid = __app_group_get_pid(h);
+
+       g_hash_table_foreach_remove(app_group_hash, __hash_table_cb,
+                       GINT_TO_POINTER(pid));
+
+       if (!prev)
+               __app_group_set_status(prev, -1, false);
+}
+
+static bool __can_recycle(app_group_h h)
+{
+       app_group_context_t *context = h->data;
+
+       if (context)
+               return context->recycle;
+
+       return false;
+}
+
+static app_group_context_t *__context_dup(const app_group_context_t *context)
+{
+       app_group_context_t *dup;
+
+       if (!context) {
+               LOGE("context is NULL.");
+               return NULL;
+       }
+
+       dup = malloc(sizeof(app_group_context_t));
+       if (!dup) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       memcpy(dup, context, sizeof(app_group_context_t));
+       return dup;
+}
+
+static void __do_recycle(app_group_context_t *context)
+{
+       const char *appid;
+       const char *pkgid;
+       amd_appinfo_h ai;
+       amd_app_status_h app_status;
+       uid_t uid;
+
+       app_status = amd_app_status_find_by_pid(context->pid);
+       uid = amd_app_status_get_uid(app_status);
+
+       if (context->fg) {
+               appid = amd_app_status_get_appid(app_status);
+               ai = amd_appinfo_find(uid, appid);
+               pkgid = amd_appinfo_get_value(ai, AMD_AIT_PKGID);
+
+               LOGD("send_signal BG %s", appid);
+               aul_send_app_status_change_signal(context->pid, appid, pkgid,
+                               STATUS_BACKGROUND, APP_TYPE_UI);
+               amd_app_status_find_service_apps(app_status, STATUS_BG,
+                               __prepare_to_suspend_services, true);
+               context->fg = false;
+       }
+       recycle_bin = g_list_append(recycle_bin, context);
+       amd_noti_send("app_group.do_recycle.end", context->pid, uid, NULL, NULL);
+}
+
+static void __app_group_remove(app_group_h h)
+{
+       app_group_context_t *context;
+       int pid;
+
+       if (!h)
+               return;
+
+       pid = __app_group_get_pid(h);
+       __group_remove(h);
+       context = __detach_context_from_recycle_bin(pid);
+       if (context)
+               free(context);
+}
+
+static int __find_second_leader(int lpid)
+{
+       app_group_context_t *ac;
+       GList *list;
+
+       list = (GList *)g_hash_table_lookup(app_group_hash,
+                       GINT_TO_POINTER(lpid));
+       if (list != NULL) {
+               list = g_list_next(list);
+               if (list != NULL) {
+                       ac = (app_group_context_t *)list->data;
+                       if (ac && ac->can_be_leader) {
+                               LOGW("found the second leader, lpid: %d, pid: %d",
+                                               lpid, ac->pid);
+                               return ac->pid;
+                       }
+               }
+       }
+
+       return -1;
+}
+
+static void __remove_leader_pid(int lpid)
+{
+       app_group_context_t *ac;
+       GList *next;
+       GList *list;
+
+       list = (GList *)g_hash_table_lookup(app_group_hash,
+                       GINT_TO_POINTER(lpid));
+       if (list != NULL) {
+               next = g_list_next(list);
+               if (next != NULL) {
+                       ac = (app_group_context_t *)list->data;
+                       if (ac)
+                               free(ac);
+                       list = g_list_delete_link(list, list);
+                       ac = (app_group_context_t *)next->data;
+                       g_hash_table_insert(app_group_hash,
+                                       GINT_TO_POINTER(ac->pid), next);
+                       g_hash_table_remove(app_group_hash,
+                                       GINT_TO_POINTER(lpid));
+               }
+       }
+}
+
+static int __get_next_caller_pid(app_group_h h)
+{
+       app_group_context_t *ac;
+
+       if (!h)
+               return -1;
+
+       h = g_list_next(h);
+       if (!h)
+               return -1;
+
+       ac = h->data;
+
+       return ac->caller_pid;
+}
+
+static bool __can_reroute(app_group_h h)
+{
+       app_group_context_t *ac;
+
+       if (!h)
+               return false;
+
+       ac = h->data;
+
+       return ac->reroute;
+}
+
+static void __reroute(app_group_h h)
+{
+       GList *before;
+       GList *after;
+       app_group_context_t *ac1;
+       app_group_context_t *ac2;
+       GList *list = h;
+
+       if (!list)
+               return;
+
+       before = g_list_previous(list);
+       after = g_list_next(list);
+       if (!before || !after)
+               return;
+
+       LOGD("reroute");
+       ac1 = (app_group_context_t *)before->data;
+       ac2 = (app_group_context_t *)after->data;
+       __attach_window(ac1->wid, ac2->wid);
+}
+
+static void __app_group_remove_full(app_group_h h, uid_t uid)
+{
+       int pid;
+       int caller_pid;
+
+       if (!h)
+               return;
+
+       pid = __app_group_get_pid(h);
+       if (__app_group_is_leader(h)) {
+               LOGW("app_group_leader_app, pid: %d", pid);
+               if (__find_second_leader(pid) == -1) {
+                       __app_group_clear_top(h, uid);
+                       __app_group_remove(h);
+               } else {
+                       __remove_leader_pid(pid);
+               }
+       } else if (__app_group_is_sub_app(h)) {
+               LOGW("app_group_sub_app, pid: %d", pid);
+               caller_pid = __get_next_caller_pid(h);
+               if (__can_reroute(h)
+                               || (caller_pid > 0 && caller_pid != pid)) {
+                       LOGW("app_group reroute");
+                       __reroute(h);
+               } else {
+                       LOGW("app_group clear top");
+                       __app_group_clear_top(h, uid);
+               }
+               __app_group_remove(h);
+       }
+}
+
+static void __app_group_remove_from_recycle_bin(int pid)
+{
+       app_group_context_t *context = __detach_context_from_recycle_bin(pid);
+
+       if (context)
+               free(context);
+}
+
+int _app_group_get_window(app_group_h h)
+{
+       app_group_context_t *context;
+
+       if (!h)
+               return -1;
+
+       context = h->data;
+       if (context)
+               return context->wid;
+
+       return -1;
+}
+
+static int __app_group_set_window(app_group_h h, int wid)
+{
+       GList *i = h;
+       GList *j;
+       int previous_wid = 0;
+       int next_wid = 0;
+       int caller_wid;
+       app_group_context_t *ac;
+       app_group_context_t *prev_ac;
+       app_group_context_t *next_ac;
+
+       if (!i)
+               return -1;
+
+       ac = i->data;
+       ac->wid = wid;
+
+       j = g_list_previous(i);
+       if (j) {
+               prev_ac = j->data;
+               previous_wid = prev_ac->wid;
+       }
+
+       j = g_list_next(i);
+       if (j) {
+               next_ac = j->data;
+               next_wid = next_ac->wid;
+       }
+
+       if (previous_wid != 0)
+               __attach_window(previous_wid, wid);
+
+       if (ac->can_shift && ac->caller_pid > 0) {
+               caller_wid = _app_group_get_window(
+                               _app_group_find(ac->caller_pid));
+               if (caller_wid != 0)
+                       __attach_window(caller_wid, wid);
+       }
+
+       if (next_wid != 0)
+               __attach_window(wid, next_wid);
+
+       return 0;
+}
+
+static void __app_group_clear_top(app_group_h h, uid_t uid)
+{
+       int wid;
+       GList *itr;
+       GList *cur;
+
+       if (!h)
+               return;
+
+       itr = g_list_last(h);
+       while (itr != NULL && itr != h) {
+               cur = itr;
+               itr = g_list_previous(itr);
+               wid = _app_group_get_window(cur);
+               __detach_window(wid);
+               aul_send_app_terminate_request_signal(__app_group_get_pid(cur),
+                               NULL, NULL, NULL);
+               amd_launch_term_sub_app(__app_group_get_pid(cur), uid);
+               __app_group_remove(cur);
+       }
+}
+
+static bool __app_group_is_group_app(bundle *kb, uid_t uid)
+{
+       const char *str;
+       const char *mode;
+       const char *appid;
+       amd_appinfo_h ai;
+
+       if (kb == NULL)
+               return false;
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       if (appid == NULL)
+               return false;
+
+       ai = amd_appinfo_find(uid, appid);
+       mode = amd_appinfo_get_value(ai, AMD_AIT_LAUNCH_MODE);
+       if (mode != NULL && strcmp(mode, "caller") == 0) {
+               str = bundle_get_val(kb, APP_SVC_K_LAUNCH_MODE);
+               if (str != NULL && strcmp(str, "group") == 0)
+                       return true;
+       } else if (mode != NULL && strcmp(mode, "group") == 0) {
+               return true;
+       }
+
+       return false;
+}
+
+static void __app_group_get_leader_pids(int *cnt, int **pids)
+{
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       int size = g_hash_table_size(app_group_hash);
+       int *leader_pids;
+       int i;
+
+       if (size > 0) {
+               leader_pids = (int *)malloc(sizeof(int) * size);
+               if (leader_pids == NULL) {
+                       LOGE("out of memory");
+                       *cnt = 0;
+                       *pids = NULL;
+                       return;
+               }
+
+               g_hash_table_iter_init(&iter, app_group_hash);
+               i = 0;
+               while (g_hash_table_iter_next(&iter, &key, &value)) {
+                       leader_pids[i] = GPOINTER_TO_INT(key);
+                       i++;
+               }
+
+               *cnt = size;
+               *pids = leader_pids;
+       } else {
+               *cnt = 0;
+               *pids = NULL;
+       }
+}
+
+void _app_group_get_group_pids(int leader_pid, int *cnt, int **pids)
+{
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       GList *list;
+       GList *i;
+       int size;
+       int *pid_array;
+       int j;
+       app_group_context_t *ac;
+
+       g_hash_table_iter_init(&iter, app_group_hash);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               if (GPOINTER_TO_INT(key) == leader_pid) {
+                       list = (GList *)value;
+                       i = g_list_first(list);
+                       size = g_list_length(list);
+                       if (size > 0) {
+                               j = 0;
+                               pid_array = (int *)malloc(sizeof(int) * size);
+                               if (pid_array == NULL) {
+                                       LOGE("out of memory");
+                                       *cnt = 0;
+                                       *pids = NULL;
+                                       return;
+                               }
+
+                               while (i != NULL) {
+                                       ac = (app_group_context_t *)i->data;
+                                       pid_array[j] = ac->pid;
+                                       i = g_list_next(i);
+                                       j++;
+                               }
+
+                               *cnt = size;
+                               *pids = pid_array;
+                       } else {
+                               *cnt = 0;
+                               *pids = NULL;
+                       }
+                       return;
+               }
+       }
+
+       *cnt = 0;
+       *pids = NULL;
+}
+
+static bool __app_group_is_sub_app(app_group_h h)
+{
+       if (!h)
+               return false;
+
+       if (g_list_previous(h))
+               return true;
+
+       return false;
+}
+
+int _app_group_get_leader_pid(app_group_h h)
+{
+       GList *list = h;
+       int lpid;
+       app_group_context_t *ac;
+
+       if (!h)
+               return -1;
+
+       list = g_list_first(list);
+       ac = list->data;
+       lpid = ac->pid;
+
+       return lpid;
+}
+
+static void __set_status(app_group_context_t *ac, app_group_context_t *last_ac,
+               int lpid, int pid, int status, bool force)
+{
+       const char *pkgid;
+       amd_app_status_h app_status;
+
+       if (status > 0)
+               ac->status = status;
+
+       if (last_ac->wid != 0 || status == STATUS_VISIBLE || force == TRUE) {
+               if (__is_visible(pid)) {
+                       __set_fg_flag(pid, 1, force);
+                       if (!ac->group_sig && lpid != pid) {
+                               app_status = amd_app_status_find_by_pid(pid);
+                               pkgid = amd_app_status_get_pkgid(app_status);
+                               LOGD("send group signal %d", pid);
+                               aul_send_app_group_signal(lpid, pid, pkgid);
+                               ac->group_sig = 1;
+                       }
+               } else {
+                       __set_fg_flag(pid, 0, force);
+               }
+       }
+}
+
+static int __app_group_set_status(app_group_h h, int status, bool force)
+{
+       GList *i = h;
+       app_group_context_t *ac;
+       app_group_context_t *last_ac;
+       app_group_context_t *first_ac;
+       int lpid;
+       int pid;
+
+       if (!i)
+               return -1;
+
+       pid = __app_group_get_pid(h);
+       ac = i->data;
+       i = g_list_last(i);
+       last_ac = i->data;
+       i = g_list_first(i);
+       first_ac = i->data;
+       lpid = first_ac->pid;
+       __set_status(ac, last_ac, lpid, pid, status, force);
+
+       return 0;
+}
+
+static bool __app_group_get_fg_flag(app_group_h h)
+{
+       app_group_context_t *ac;
+
+       if (!h)
+               return false;
+
+       ac = h->data;
+
+       return ac->fg;
+}
+
+static int __app_group_can_start_app(const char *appid, bundle *b,
+               bool *can_attach, int *lpid, app_group_launch_mode *mode,
+               uid_t uid)
+{
+       const char *val;
+       int caller_pid;
+       int caller_wid;
+       app_group_h h;
+       int ret = 0;
+
+       *can_attach = false;
+
+       if (__can_attach_window(b, appid, mode, uid)) {
+               *can_attach = true;
+               val = bundle_get_val(b, AUL_K_ORG_CALLER_PID);
+               if (val == NULL)
+                       val = bundle_get_val(b, AUL_K_CALLER_PID);
+
+               if (val == NULL) {
+                       LOGE("no caller pid");
+                       ret = -1;
+                       goto err;
+               }
+
+               caller_pid = atoi(val);
+               h = _app_group_find(caller_pid);
+               *lpid = _app_group_get_leader_pid(h);
+               if (*lpid != -1) {
+                       caller_wid = _app_group_get_window(h);
+                       if (caller_wid == 0) {
+                               LOGD("caller window wasn't ready");
+                               if (__can_be_leader(b))
+                                       *can_attach = false;
+                               else
+                                       *can_attach = true;
+                       }
+               } else {
+                       LOGE("no lpid");
+                       if (__can_be_leader(b)) {
+                               *can_attach = false;
+                       } else {
+                               ret = -1;
+                               goto err;
+                       }
+               }
+       }
+
+err:
+       __launch_context.can_attach = *can_attach;
+       __launch_context.mode = *mode;
+       __launch_context.lpid = *lpid;
+
+       return ret;
+}
+
+static app_group_context_t *__group_add(int leader_pid, int pid,
+               app_group_launch_mode mode, int caller_pid, bool can_shift,
+               bool recycle)
+{
+       app_group_context_t *ac = NULL;
+       GList *list;
+       GList *tmp_list;
+       app_group_h h;
+
+       ac = __detach_context_from_recycle_bin(pid);
+       if (ac == NULL) {
+               ac = calloc(1, sizeof(app_group_context_t));
+               if (ac == NULL) {
+                       LOGE("out of memory");
+                       return NULL;
+               }
+               ac->pid = pid;
+               ac->wid = 0;
+               ac->fg = false;
+               ac->can_be_leader = false;
+               ac->reroute = false;
+               ac->launch_mode = mode;
+               ac->caller_pid = caller_pid;
+               ac->can_shift = can_shift;
+               ac->recycle = recycle;
+       }
+
+       if (leader_pid == pid || ac->recycle)
+               ac->group_sig = true;
+       else
+               ac->group_sig = false;
+
+       list = (GList *)g_hash_table_lookup(app_group_hash,
+                       GINT_TO_POINTER(leader_pid));
+       if (list != NULL) {
+               tmp_list = g_list_find_custom(list, GINT_TO_POINTER(pid),
+                               __comp_pid);
+               if (tmp_list != NULL) {
+                       LOGE("pid exist");
+                       free(ac);
+                       return NULL;
+               }
+       }
+
+       list = g_list_append(list, ac);
+       g_hash_table_insert(app_group_hash, GINT_TO_POINTER(leader_pid), list);
+
+       if (ac->wid != 0) {
+               h = _app_group_find(pid);
+               __app_group_set_window(h, ac->wid);
+       }
+
+       return ac;
+}
+
+static int __set_hint(app_group_context_t *ac, bundle *kb)
+{
+       char *str_leader = NULL;
+       char *str_reroute = NULL;
+
+       if (!kb || !ac)
+               return -1;
+
+       bundle_get_str(kb, AUL_SVC_K_CAN_BE_LEADER, &str_leader);
+       bundle_get_str(kb, AUL_SVC_K_REROUTE, &str_reroute);
+
+       if (str_leader && !strcmp(str_leader, "true"))
+               ac->can_be_leader = true;
+       if (str_reroute && !strcmp(str_reroute, "true"))
+               ac->reroute = true;
+       return 0;
+}
+
+static void __app_group_start_app(int pid, bundle *b, int lpid, bool can_attach,
+               app_group_launch_mode mode)
+{
+       int caller_pid = __get_caller_pid(b);
+       bool can_shift = false;
+       bool recycle = false;
+       const char *str;
+       app_group_context_t *ac;
+
+       LOGD("app_group_start_app");
+
+       str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW);
+       if (str != NULL && strcmp(str, "true") == 0)
+               can_shift = true;
+
+       str = bundle_get_val(b, AUL_SVC_K_RECYCLE);
+       if (str != NULL && strcmp(str, "true") == 0)
+               recycle = true;
+
+       if (can_attach)
+               ac = __group_add(lpid, pid, mode, caller_pid, false, recycle);
+       else
+               ac = __group_add(pid, pid, mode, caller_pid, can_shift, false);
+       __set_hint(ac, b);
+}
+
+static void __app_group_lower(app_group_h h, bool *exit)
+{
+       app_group_context_t *ac;
+
+       if (!h)
+               return;
+
+       ac = h->data;
+       if (__app_group_is_sub_app(h)) {
+               if (__can_recycle(h) && __can_reroute(h)) {
+                       __reroute(h);
+                       if (ac->wid != 0)
+                               __detach_window(ac->wid);
+
+                       ac = __context_dup(ac);
+                       __group_remove(h);
+                       __do_recycle(ac);
+                       *exit = false;
+               } else {
+                       *exit = true;
+               }
+
+               return;
+       }
+
+       *exit = false;
+       if (ac->can_shift) {
+               __detach_window(ac->wid);
+               ac->can_shift = false;
+               __lower_window(ac->wid);
+       }
+}
+
+static void __app_group_restart_app(app_group_h h, bundle *b)
+{
+       app_group_context_t *ac;
+       const char *pid_str;
+       int cwid;
+
+       if (!b || !h)
+               return;
+
+       ac = h->data;
+       ac->caller_pid = __get_caller_pid(b);
+       if (ac->can_shift) {
+               if (ac->wid != 0)
+                       __detach_window(ac->wid);
+               ac->can_shift = false;
+       }
+
+       pid_str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW);
+       if (pid_str && !strcmp(pid_str, "true")) {
+               ac->can_shift = true;
+               if (ac->wid != 0) {
+                       if (ac->caller_pid > 0) {
+                               cwid = _app_group_get_window(
+                                       _app_group_find(ac->caller_pid));
+                               if (cwid != 0)
+                                       __attach_window(cwid, ac->wid);
+                               else
+                                       LOGE("invalid caller wid");
+                       } else {
+                               LOGE("invalid caller pid");
+                       }
+               }
+       }
+}
+
+static int __app_group_find_pid_from_recycle_bin(const char *appid)
+{
+       app_group_context_t *ac;
+       amd_app_status_h app_status;
+       const char *appid_from_bin;
+       GList *iter = recycle_bin;
+
+       while (iter) {
+               ac = (app_group_context_t *)iter->data;
+               app_status = amd_app_status_find_by_pid(ac->pid);
+               appid_from_bin = amd_app_status_get_appid(app_status);
+               if (appid && appid_from_bin && !strcmp(appid, appid_from_bin))
+                       return ac->pid;
+
+               iter = g_list_next(iter);
+       }
+
+       return -1;
+}
+
+static void __app_group_get_idle_pids(int *cnt, int **pids)
+{
+       GList *iter = recycle_bin;
+       int idle_cnt = g_list_length(iter);
+       int *idle_pids;
+       int i = 0;
+       app_group_context_t *ac;
+
+       if (idle_cnt <= 0) {
+               *cnt = 0;
+               *pids = NULL;
+               return;
+       }
+
+       idle_pids = (int *)malloc(sizeof(int) * idle_cnt);
+       if (idle_pids == NULL) {
+               LOGE("Out-of-memory");
+               *cnt = 0;
+               *pids = NULL;
+               return;
+       }
+
+       while (iter) {
+               ac = (app_group_context_t *)iter->data;
+               idle_pids[i] = ac->pid;
+               iter = g_list_next(iter);
+               i++;
+       }
+
+       *cnt = idle_cnt;
+       *pids = idle_pids;
+}
+
+static int __app_group_activate_below(app_group_h h, const char *below_appid)
+{
+       app_group_context_t *context;
+       int wid;
+       int tpid;
+       GList *list;
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       amd_app_status_h app_status;
+       const char *appid;
+
+       if (!h) {
+               LOGE("Invalid handle");
+               return -1;
+       }
+
+       context = h->data;
+       if (context->wid == 0) {
+               LOGE("Caller wid was 0");
+               return -1;
+       }
+
+       if (!below_appid) {
+               LOGE("below_appid was null");
+               return -1;
+       }
+
+       wid = context->wid;
+       g_hash_table_iter_init(&iter, app_group_hash);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               tpid = GPOINTER_TO_INT(key);
+               app_status = amd_app_status_find_by_pid(tpid);
+               appid = amd_app_status_get_appid(app_status);
+               if (appid && strcmp(appid, below_appid) == 0) {
+                       list = (GList *)value;
+                       context  = (app_group_context_t *)list->data;
+                       __activate_below(wid, context->wid);
+                       return 0;
+               }
+       }
+
+       LOGE("Failed to find available appid to move");
+       return -1;
+}
+
+static int __app_group_activate_above(app_group_h h, const char *above_appid)
+{
+       app_group_context_t *context;
+       int wid;
+       int tpid;
+       GList *list;
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       amd_app_status_h app_status;
+       const char *appid;
+
+       if (!h) {
+               LOGE("Invalid handle");
+               return -1;
+       }
+
+       context = h->data;
+       if (context->wid == 0) {
+               LOGE("Caller wid was 0");
+               return -1;
+       }
+
+       if (!above_appid) {
+               LOGE("below_appid was null");
+               return -1;
+       }
+
+       wid = context->wid;
+       g_hash_table_iter_init(&iter, app_group_hash);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               tpid = GPOINTER_TO_INT(key);
+               app_status = amd_app_status_find_by_pid(tpid);
+               appid = amd_app_status_get_appid(app_status);
+               if (appid && strcmp(appid, above_appid) == 0) {
+                       list = (GList *)value;
+                       context  = (app_group_context_t *)list->data;
+                       __activate_above(wid, context->wid);
+                       return 0;
+               }
+       }
+
+       LOGE("Failed to find available appid to move");
+       return -1;
+}
+
+static int __app_group_attach(const char *parent_appid, const char *child_appid,
+               uid_t uid)
+{
+       amd_app_status_h status;
+       int ppid;
+       int cpid;
+       int pwid;
+       int cwid;
+
+       status = amd_app_status_find_by_appid(parent_appid, uid);
+       if (!status) {
+               LOGE("parent app is not running %s", parent_appid);
+               return -1;
+       }
+
+       ppid = amd_app_status_get_pid(status);
+       status = amd_app_status_find_by_appid(child_appid, uid);
+       if (!status) {
+               LOGE("child app is not running %s", child_appid);
+               return -1;
+       }
+
+       pwid = _app_group_get_window(_app_group_find(ppid));
+       if (pwid == 0) {
+               LOGE("window wasn't ready - ppid(%d)", ppid);
+               return -1;
+       }
+
+       cpid = amd_app_status_get_pid(status);
+       cwid = _app_group_get_window(_app_group_find(cpid));
+       if (cwid == 0) {
+               LOGE("window wasn't ready - cpid(%d)", cpid);
+               return -1;
+       }
+
+       __attach_window(pwid, cwid);
+
+       return 0;
+}
+
+static int __app_group_detach(const char *child_appid, uid_t uid)
+{
+       amd_app_status_h status;
+       int cpid;
+       int cwid;
+
+       status = amd_app_status_find_by_appid(child_appid, uid);
+       if (!status) {
+               LOGE("child app is not running %s", child_appid);
+               return -1;
+       }
+
+       cpid = amd_app_status_get_pid(status);
+       cwid = _app_group_get_window(_app_group_find(cpid));
+       if (cwid == 0) {
+               LOGE("window wasn't ready : %d", cwid);
+               return -1;
+       }
+
+       __detach_window(cwid);
+
+       return 0;
+}
+
+static int __dispatch_app_group_get_window(amd_request_h req)
+{
+       char *buf;
+       int pid;
+       int wid;
+
+       bundle_get_str(amd_request_get_bundle(req), AUL_K_PID, &buf);
+       pid = atoi(buf);
+       wid = _app_group_get_window(_app_group_find(pid));
+       amd_request_send_result(req, wid);
+
+       return 0;
+}
+
+static int __dispatch_app_group_set_window(amd_request_h req)
+{
+       char *buf;
+       int pid = amd_request_get_pid(req);
+       uid_t uid = amd_request_get_target_uid(req);
+       int wid;
+       int ret;
+
+       bundle_get_str(amd_request_get_bundle(req), AUL_K_WID, &buf);
+       wid = atoi(buf);
+       ret = __app_group_set_window(_app_group_find(pid), wid);
+       LOGD("pid(%d), wid(%d), result(%d)", pid, wid, ret);
+       _screen_connector_add_app_screen(pid, wid, NULL, uid);
+       amd_noti_send("app_group.window.set", pid, wid, NULL, NULL);
+
+       return ret;
+}
+
+static int __dispatch_app_group_get_fg_flag(amd_request_h req)
+{
+       char *buf;
+       int pid;
+       bool fg;
+
+       bundle_get_str(amd_request_get_bundle(req), AUL_K_PID, &buf);
+       pid = atoi(buf);
+       fg = __app_group_get_fg_flag(_app_group_find(pid));
+       amd_request_send_result(req, (int)fg);
+
+       return 0;
+}
+
+static int __dispatch_app_group_clear_top(amd_request_h req)
+{
+       int pid = amd_request_get_pid(req);
+       uid_t uid = amd_request_get_target_uid(req);
+
+       __app_group_clear_top(_app_group_find(pid), uid);
+       amd_request_send_result(req, 0);
+
+       return 0;
+}
+
+static int __dispatch_app_group_get_leader_pid(amd_request_h req)
+{
+       char *buf;
+       int pid;
+       int lpid;
+
+       bundle_get_str(amd_request_get_bundle(req), AUL_K_PID, &buf);
+       pid = atoi(buf);
+       lpid = _app_group_get_leader_pid(_app_group_find(pid));
+       amd_request_send_result(req, lpid);
+
+       return 0;
+}
+
+static int __dispatch_app_group_get_leader_pids(amd_request_h req)
+{
+       int cnt;
+       int *pids;
+       unsigned char empty[1] = {0,};
+
+       __app_group_get_leader_pids(&cnt, &pids);
+
+       if (pids == NULL || cnt == 0) {
+               amd_request_send_raw(req, APP_GROUP_GET_LEADER_PIDS, empty, 0);
+       } else {
+               amd_request_send_raw(req, APP_GROUP_GET_LEADER_PIDS,
+                               (unsigned char *)pids, cnt * sizeof(int));
+       }
+
+       if (pids != NULL)
+               free(pids);
+
+       return 0;
+}
+
+static int __dispatch_app_group_get_idle_pids(amd_request_h req)
+{
+       int cnt;
+       int *pids;
+       unsigned char empty[1] = {0,};
+
+       __app_group_get_idle_pids(&cnt, &pids);
+       if (pids == NULL || cnt == 0) {
+               amd_request_send_raw(req, APP_GROUP_GET_IDLE_PIDS, empty, 0);
+       } else {
+               amd_request_send_raw(req, APP_GROUP_GET_IDLE_PIDS,
+                               (unsigned char *)pids, cnt * sizeof(int));
+       }
+
+       if (pids != NULL)
+               free(pids);
+
+       return 0;
+}
+
+static int __dispatch_app_group_get_group_pids(amd_request_h req)
+{
+       char *buf;
+       int leader_pid;
+       int cnt;
+       int *pids;
+       unsigned char empty[1] = { 0 };
+
+       bundle_get_str(amd_request_get_bundle(req), AUL_K_LEADER_PID, &buf);
+       leader_pid = atoi(buf);
+
+       _app_group_get_group_pids(leader_pid, &cnt, &pids);
+       if (pids == NULL || cnt == 0) {
+               amd_request_send_raw(req, APP_GROUP_GET_GROUP_PIDS, empty, 0);
+       } else {
+               amd_request_send_raw(req, APP_GROUP_GET_GROUP_PIDS,
+                               (unsigned char *)pids, cnt * sizeof(int));
+       }
+
+       if (pids != NULL)
+               free(pids);
+
+       return 0;
+}
+
+static int __dispatch_app_group_lower(amd_request_h req)
+{
+       bool ret = false;
+
+       __app_group_lower(_app_group_find(amd_request_get_pid(req)), &ret);
+       amd_request_send_result(req, (int)ret);
+
+       return 0;
+}
+
+static int __dispatch_app_group_activate_below(amd_request_h req)
+{
+       char *buf = NULL;
+       int ret;
+       app_group_h app_group;
+
+       bundle_get_str(amd_request_get_bundle(req), AUL_K_APPID, &buf);
+       app_group = _app_group_find(amd_request_get_pid(req));
+       ret = __app_group_activate_below(app_group, buf);
+       amd_request_send_result(req, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_group_activate_above(amd_request_h req)
+{
+       char *buf = NULL;
+       int ret;
+       app_group_h app_group;
+
+       bundle_get_str(amd_request_get_bundle(req), AUL_K_APPID, &buf);
+       app_group = _app_group_find(amd_request_get_pid(req));
+       ret = __app_group_activate_above(app_group, buf);
+       amd_request_send_result(req, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_window_attach(amd_request_h req)
+{
+       bundle *b = amd_request_get_bundle(req);
+       const char *parent_appid;
+       const char *child_appid;
+       int ret;
+       uid_t uid = amd_request_get_target_uid(req);
+
+       if (!b) {
+               LOGE("Invalid bundle");
+               amd_request_send_result(req, -1);
+               return -1;
+       }
+
+       parent_appid = bundle_get_val(b, AUL_K_PARENT_APPID);
+       if (!parent_appid) {
+               LOGE("Invalid parameters");
+               amd_request_send_result(req, -1);
+               return -1;
+       }
+
+       child_appid = bundle_get_val(b, AUL_K_CHILD_APPID);
+       if (!child_appid) {
+               LOGE("Invalid parameters");
+               amd_request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = __app_group_attach(parent_appid, child_appid, uid);
+       amd_request_send_result(req, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_window_detach(amd_request_h req)
+{
+       bundle *b = amd_request_get_bundle(req);
+       const char *child_appid;
+       int ret;
+       uid_t uid = amd_request_get_target_uid(req);
+
+       if (!b) {
+               LOGE("Invalid bundle");
+               amd_request_send_result(req, -1);
+               return -1;
+       }
+
+       child_appid = bundle_get_val(b, AUL_K_CHILD_APPID);
+       if (!child_appid) {
+               LOGE("Invalid parameters");
+               amd_request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = __app_group_detach(child_appid, uid);
+       amd_request_send_result(req, ret);
+
+       return 0;
+}
+
+static amd_request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = APP_GROUP_GET_WINDOW,
+               .callback = __dispatch_app_group_get_window
+       },
+       {
+               .cmd = APP_GROUP_SET_WINDOW,
+               .callback = __dispatch_app_group_set_window
+       },
+       {
+               .cmd = APP_GROUP_GET_FG,
+               .callback = __dispatch_app_group_get_fg_flag
+       },
+       {
+               .cmd = APP_GROUP_GET_LEADER_PID,
+               .callback = __dispatch_app_group_get_leader_pid
+       },
+       {
+               .cmd = APP_GROUP_GET_LEADER_PIDS,
+               .callback = __dispatch_app_group_get_leader_pids
+       },
+       {
+               .cmd = APP_GROUP_GET_GROUP_PIDS,
+               .callback = __dispatch_app_group_get_group_pids
+       },
+       {
+               .cmd = APP_GROUP_GET_IDLE_PIDS,
+               .callback = __dispatch_app_group_get_idle_pids
+       },
+       {
+               .cmd = APP_GROUP_LOWER,
+               .callback = __dispatch_app_group_lower
+       },
+       {       .cmd = APP_GROUP_CLEAR_TOP,
+               .callback = __dispatch_app_group_clear_top
+       },
+       {
+               .cmd = APP_GROUP_ACTIVATE_BELOW,
+               .callback = __dispatch_app_group_activate_below
+       },
+       {
+               .cmd = APP_GROUP_ACTIVATE_ABOVE,
+               .callback = __dispatch_app_group_activate_above
+       },
+       {
+               .cmd = APP_WINDOW_ATTACH,
+               .callback = __dispatch_app_window_attach
+       },
+       {       .cmd = APP_WINDOW_DETACH,
+               .callback = __dispatch_app_window_detach
+       },
+};
+
+static amd_cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = APP_WINDOW_ATTACH,
+               .checker = amd_cynara_simple_checker,
+               .data = PRIVILEGE_PLATFORM
+       },
+       {
+               .cmd = APP_WINDOW_DETACH,
+               .checker = amd_cynara_simple_checker,
+               .data = PRIVILEGE_PLATFORM
+       },
+};
+
+static int __on_app_status_cleanup(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid;
+       uid_t uid;
+       amd_app_status_h status = arg3;
+
+       if (status == NULL)
+               return -1;
+
+       pid = amd_app_status_get_pid(status);
+       uid = amd_app_status_get_uid(status);
+
+       __app_group_remove_full(_app_group_find(pid), uid);
+       __app_group_remove_from_recycle_bin(pid);
+
+       return 0;
+}
+
+static int __on_status_update(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       bool force = arg1;
+       bool update_group_info = arg2;
+       amd_app_status_h app_status = arg3;
+       app_group_h app_group;
+
+       if (update_group_info) {
+               app_group = _app_group_find(amd_app_status_get_pid(app_status));
+               __app_group_set_status(app_group,
+                               amd_app_status_get_status(app_status), force);
+       }
+
+       return 0;
+}
+
+static int __on_term_app(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       amd_request_h req = arg3;
+       int *pids = NULL;
+       int i;
+       int cnt = 0;
+       uid_t uid = amd_request_get_target_uid(req);
+
+       if (__app_group_is_leader(_app_group_find(pid))) {
+               _app_group_get_group_pids(pid, &cnt, &pids);
+               for (i = cnt - 1; i >= 0; i--) {
+                       if (i != 0)
+                               amd_launch_term_sub_app(pids[i], uid);
+                       __app_group_remove(_app_group_find(pids[i]));
+               }
+               free(pids);
+       }
+
+       return 0;
+}
+
+static int __on_term_bgapp(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       amd_request_h req = arg3;
+       int *pids = NULL;
+       int i;
+       int cnt = 0;
+       int status = -1;
+       amd_app_status_h app_status;
+       uid_t uid = amd_request_get_target_uid(req);
+       app_group_h app_group;
+
+       if (__app_group_is_leader(_app_group_find(pid))) {
+               _app_group_get_group_pids(pid, &cnt, &pids);
+               if (cnt > 0) {
+                       app_status = amd_app_status_find_by_pid(pids[cnt - 1]);
+                       status = amd_app_status_get_status(app_status);
+                       if (status == STATUS_BG) {
+                               for (i = cnt - 1 ; i >= 0; i--) {
+                                       if (i != 0)
+                                               amd_launch_term_sub_app(pids[i], uid);
+                                       app_group = _app_group_find(pids[i]);
+                                       __app_group_remove(app_group);
+                               }
+                       }
+               }
+               free(pids);
+       }
+
+       return 0;
+}
+
+static int __on_app_register_pid(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       amd_appinfo_h ai = arg3;
+       bundle *kb = data;
+       const char *component_type;
+
+       component_type = amd_appinfo_get_value(ai, AMD_AIT_COMPTYPE);
+       if (component_type && strcmp(component_type, APP_TYPE_UI) == 0) {
+               __app_group_start_app(pid, kb, pid, FALSE,
+                               APP_GROUP_LAUNCH_MODE_SINGLE);
+       }
+
+       return 0;
+}
+
+static int __on_launch_complete(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       amd_appinfo_h ai = arg3;
+       bundle *kb = data;
+       const char *comp_type;
+       bool new_process = arg2;
+
+       comp_type = amd_appinfo_get_value(ai, AMD_AIT_COMPTYPE);
+       if (comp_type && !strcmp(comp_type, APP_TYPE_UI)) {
+               if (new_process) {
+                       LOGD("Add app group info %d", pid);
+                       __app_group_start_app(pid, kb, __launch_context.lpid,
+                                       __launch_context.can_attach,
+                                       __launch_context.mode);
+               } else {
+                       __app_group_restart_app(_app_group_find(pid), kb);
+               }
+       }
+
+       return 0;
+}
+
+static int __on_launch_prepare_ui_start(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int status = arg1;
+       uid_t uid = arg2;
+       amd_launch_context_h h = arg3;
+       bundle *kb = data;
+       int pid = amd_launch_context_get_pid(h);
+       const char *appid = amd_launch_context_get_appid(h);
+       bool can_attach = false;
+       int lpid = -1;
+       app_group_launch_mode mode = APP_GROUP_LAUNCH_MODE_SINGLE;
+       int ret;
+
+       if (__app_group_is_group_app(kb, uid)) {
+               amd_launch_context_set_pid(h, -1);
+               amd_launch_context_set_subapp(h, true);
+               amd_launch_context_set_app_status(h, NULL);
+       } else {
+               if (amd_launch_context_is_new_instance(h))
+                       amd_launch_context_set_subapp(h, true);
+               else
+                       amd_launch_context_set_subapp(h, false);
+       }
+
+       if (pid <= 0 || status == STATUS_DYING) {
+               ret = __app_group_can_start_app(appid, kb, &can_attach,
+                               &lpid, &mode, uid);
+               if (ret != 0) {
+                       LOGE("can't make group info");
+                       return -1;
+               }
+
+               if (can_attach && lpid == -1) {
+                       LOGE("can't launch singleton app in the same group");
+                       return -1;
+               }
+       }
+
+       if (pid == -1 && can_attach) {
+               pid = __app_group_find_pid_from_recycle_bin(appid);
+               amd_launch_context_set_pid(h, pid);
+       }
+
+       return 0;
+}
+
+static void __terminate_unmanageable_app(amd_app_status_h app_status)
+{
+       const char *appid = NULL;
+       int cnt = 0;
+       int *pids = NULL;
+       int i;
+       const char *taskmanage = NULL;
+       amd_appinfo_h ai = NULL;
+       bool bg_allowed;
+       amd_app_status_h status_h;
+       int st;
+       uid_t uid;
+
+       if (!amd_app_status_is_home_app(app_status))
+               return;
+
+       __app_group_get_leader_pids(&cnt, &pids);
+       if (pids == NULL)
+               return;
+
+       for (i = 0; i < cnt; i++) {
+               status_h = amd_app_status_find_by_pid(pids[i]);
+               if (!status_h)
+                       continue;
+
+               if (amd_app_status_is_home_app(status_h))
+                       continue;
+
+               appid = amd_app_status_get_appid(status_h);
+               ai = amd_appinfo_find(amd_app_status_get_uid(status_h), appid);
+               taskmanage = amd_appinfo_get_value(ai, AMD_AIT_TASKMANAGE);
+               bg_allowed = amd_suspend_is_allowed_background(ai);
+               uid = amd_app_status_get_uid(status_h);
+
+               if (taskmanage && strcmp("false", taskmanage) == 0
+                       && bg_allowed == false) {
+                       st = amd_app_status_get_status(status_h);
+                       if (st == STATUS_BG) {
+                               LOGW("terminate %d %s %d", pids[i], appid, st);
+                               aul_send_app_terminate_request_signal(pids[i],
+                                               NULL, NULL, NULL);
+                               amd_launch_term_sub_app(pids[i], uid);
+                       }
+               }
+       }
+
+       free(pids);
+}
+
+static tizen_profile_t __get_tizen_profile(void)
+{
+       static tizen_profile_t profile = TIZEN_PROFILE_UNKNOWN;
+       char *profile_name = NULL;
+
+       if (__builtin_expect(profile != TIZEN_PROFILE_UNKNOWN, 1))
+               return profile;
+
+       system_info_get_platform_string("http://tizen.org/feature/profile",
+                       &profile_name);
+       if (profile_name == NULL)
+               return profile;
+
+       switch (*profile_name) {
+       case 'm':
+       case 'M':
+               profile = TIZEN_PROFILE_MOBILE;
+               break;
+       case 'w':
+       case 'W':
+               profile = TIZEN_PROFILE_WEARABLE;
+               break;
+       case 't':
+       case 'T':
+               profile = TIZEN_PROFILE_TV;
+               break;
+       case 'i':
+       case 'I':
+               profile = TIZEN_PROFILE_IVI;
+               break;
+       default: /* common or unknown ==> ALL ARE COMMON. */
+               profile = TIZEN_PROFILE_COMMON;
+               break;
+       }
+       free(profile_name);
+
+       return profile;
+}
+
+static int __on_launch_status_fg(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_app_status_h app_status = arg3;
+
+       if (TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP)
+               __terminate_unmanageable_app(app_status);
+
+       return 0;
+}
+
+static int __on_app_status_add(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_app_status_h app_status = arg3;
+       int app_type = amd_app_status_get_app_type(app_status);
+       int pid;
+       int leader_pid;
+       app_group_h app_group;
+
+       if (app_type == AMD_AT_UI_APP) {
+               pid = amd_app_status_get_pid(app_status);
+               app_group = _app_group_find(pid);
+               leader_pid = _app_group_get_leader_pid(app_group);
+               amd_app_status_set_leader_pid(app_status, leader_pid);
+       }
+
+       return 0;
+}
+
+static gint __compare_app_status_for_sorting(gconstpointer p1, gconstpointer p2)
+{
+       amd_app_status_h app_status1 = (amd_app_status_h)p1;
+       amd_app_status_h app_status2 = (amd_app_status_h)p2;
+       int app_group_cnt1;
+       int app_group_cnt2;
+       int *app_group_pids1;
+       int *app_group_pids2;
+       int fg_cnt1;
+       int fg_cnt2;
+       int timestamp1;
+       int timestamp2;
+
+       if (amd_app_status_get_app_type(app_status1) != AMD_AT_UI_APP ||
+                       amd_app_status_get_app_type(app_status2) != AMD_AT_UI_APP)
+               return 0;
+
+       timestamp1 = amd_app_status_get_timestamp(app_status1);
+       timestamp2 = amd_app_status_get_timestamp(app_status2);
+       if (timestamp1 > timestamp2)
+               return 1;
+       else if (timestamp1 < timestamp2)
+               return -1;
+
+       _app_group_get_group_pids(amd_app_status_get_leader_pid(app_status1),
+                       &app_group_cnt1, &app_group_pids1);
+       _app_group_get_group_pids(amd_app_status_get_leader_pid(app_status2),
+                       &app_group_cnt2, &app_group_pids2);
+       free(app_group_pids1);
+       free(app_group_pids2);
+
+       if (app_group_cnt1 < app_group_cnt2)
+               return 1;
+       else if (app_group_cnt1 > app_group_cnt2)
+               return -1;
+
+       fg_cnt1 = amd_app_status_get_fg_cnt(app_status1);
+       fg_cnt2 = amd_app_status_get_fg_cnt(app_status2);
+       if (fg_cnt1 > fg_cnt2)
+               return 1;
+       else if (fg_cnt1 < fg_cnt2)
+               return -1;
+
+       return 0;
+}
+
+static int __on_app_status_term_bg_apps(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_app_status_term_bg_apps(__compare_app_status_for_sorting);
+
+       return 0;
+}
+
+static int __on_wl_listener(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       uint32_t id = (uint32_t)arg1;
+       struct wl_registry *reg = (struct wl_registry *)arg3;
+
+       if (!tz_policy) {
+               tz_policy = wl_registry_bind(reg, id,
+                               &tizen_policy_interface, 1);
+               amd_wayland_set_tizen_policy(tz_policy);
+               LOGD("tz_policy(%p)", tz_policy);
+       }
+
+       return 0;
+}
+
+static int __on_wl_listener_remove(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       if (tz_policy) {
+               tizen_policy_destroy(tz_policy);
+               tz_policy = NULL;
+               amd_wayland_set_tizen_policy(tz_policy);
+       }
+
+       return 0;
+}
+
+int _app_group_init(void)
+{
+       int r;
+
+       LOGD("app group init");
+       app_group_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                       NULL, NULL);
+       if (app_group_hash == NULL) {
+               LOGE("Failed to create app group hash");
+               return -1;
+       }
+
+       r = amd_request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               LOGE("Failed to register cmds");
+               return -1;
+       }
+
+       r = amd_cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (r < 0) {
+               LOGE("Failed to register checkers");
+               return -1;
+       }
+
+       amd_noti_listen("wayland.listener.tizen_policy", __on_wl_listener);
+       amd_noti_listen("wayland.listener_remove", __on_wl_listener_remove);
+       amd_noti_listen("app_status.cleanup", __on_app_status_cleanup);
+       amd_noti_listen("app_status.update_status.end", __on_status_update);
+       amd_noti_listen("launch.term_app.start", __on_term_app);
+       amd_noti_listen("launch.term_bgapp.start", __on_term_bgapp);
+       amd_noti_listen("app_status.app_register_pid", __on_app_register_pid);
+       amd_noti_listen("launch.complete.start", __on_launch_complete);
+       amd_noti_listen("launch.prepare.ui.start", __on_launch_prepare_ui_start);
+       amd_noti_listen("launch.status.fg", __on_launch_status_fg);
+       amd_noti_listen("app_status.add", __on_app_status_add);
+       amd_noti_listen("app_status.term_bg_apps", __on_app_status_term_bg_apps);
+
+       return 0;
+}
+
+void _app_group_fini(void)
+{
+       LOGD("app group fini");
+       /* TODO: Destroy app group info */
+}
diff --git a/modules/ui-core/src/amd_screen_connector.c b/modules/ui-core/src/amd_screen_connector.c
new file mode 100644 (file)
index 0000000..9bd0196
--- /dev/null
@@ -0,0 +1,1031 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+#include <bundle_internal.h>
+#include <dlog.h>
+#include <aul.h>
+#include <aul_sock.h>
+#include <aul_screen_connector.h>
+
+#include "amd.h"
+#include "amd_app_group.h"
+#include "amd_screen_connector.h"
+
+#define SUSPEND_INTERVAL 5 /* sec */
+#undef LOG_TAG
+#define LOG_TAG "AMD_SCREEN_CONNECTOR"
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+struct app_screen_s {
+       char *appid;
+       char *instance_id;
+       int pid;
+       uid_t uid;
+       unsigned int surf;
+       int screen_type;
+       int caller_pid;
+};
+
+struct viewer_info_s {
+       int pid;
+       int screen_type;
+       bool priv;
+       unsigned int ref;
+};
+
+struct user_info_s {
+       uid_t uid;
+       GList *screen_viewer_list;
+       GList *app_screen_list;
+};
+
+static GHashTable *user_table;
+
+static struct app_screen_s *__create_app_screen(int pid, uid_t uid,
+               const char *appid, unsigned int surf, const char *instance_id,
+               int screen_type, int caller_pid)
+{
+       struct app_screen_s *app_screen;
+
+       app_screen = calloc(1, sizeof(struct app_screen_s));
+       if (app_screen == NULL) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       app_screen->appid = strdup(appid);
+       if (app_screen->appid == NULL) {
+               LOGE("out of memory");
+               free(app_screen);
+               return NULL;
+       }
+
+       app_screen->instance_id = strdup(instance_id);
+       if (app_screen->instance_id == NULL) {
+               LOGE("out of memory");
+               free(app_screen->appid);
+               free(app_screen);
+               return NULL;
+       }
+
+       app_screen->pid = pid;
+       app_screen->uid = uid;
+       app_screen->surf = surf;
+       app_screen->screen_type = screen_type;
+       app_screen->caller_pid = caller_pid;
+
+       return app_screen;
+}
+
+static void __destroy_app_screen(gpointer data)
+{
+       struct app_screen_s *app_screen = (struct app_screen_s *)data;
+
+       if (app_screen == NULL)
+               return;
+
+       if (app_screen->instance_id)
+               free(app_screen->instance_id);
+       if (app_screen->appid)
+               free(app_screen->appid);
+       free(app_screen);
+}
+
+static gint __compare_instance_id(gconstpointer a, gconstpointer b)
+{
+       struct app_screen_s *app_screen = (struct app_screen_s *)a;
+       const char *instance_id = (const char *)b;
+
+       if (app_screen == NULL || instance_id == NULL)
+               return -1;
+
+       if (!strcmp(app_screen->instance_id, instance_id))
+               return 0;
+
+       return -1;
+}
+
+static struct viewer_info_s *__create_viewer_info(int pid, int screen_type,
+               bool priv, unsigned int ref)
+{
+       struct viewer_info_s *viewer_info;
+
+       viewer_info = calloc(1, sizeof(struct viewer_info_s));
+       if (viewer_info == NULL) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       viewer_info->pid = pid;
+       viewer_info->screen_type = screen_type;
+       viewer_info->priv = priv;
+       viewer_info->ref = ref;
+
+       return viewer_info;
+}
+
+static void __destroy_user_info(gpointer data)
+{
+       struct user_info_s *user_info = (struct user_info_s *)data;
+
+       if (user_info == NULL)
+               return;
+
+       if (user_info->app_screen_list) {
+               g_list_free_full(user_info->app_screen_list,
+                               __destroy_app_screen);
+       }
+       if (user_info->screen_viewer_list)
+               g_list_free_full(user_info->screen_viewer_list, free);
+       free(user_info);
+}
+
+static struct user_info_s *__create_user_info(uid_t uid)
+{
+       struct user_info_s *user_info;
+
+       user_info = malloc(sizeof(struct user_info_s));
+       if (user_info == NULL) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       user_info->uid = uid;
+       user_info->screen_viewer_list = NULL;
+       user_info->app_screen_list = NULL;
+
+       return user_info;
+}
+
+static bundle *__create_bundle(struct app_screen_s *app_screen,
+               const char *event)
+{
+       bundle *b;
+
+       b = bundle_create();
+       if (b == NULL) {
+               LOGE("out of memory");
+               return NULL;
+       }
+
+       bundle_add_str(b, "__AUL_SC_EVENT__", event);
+       bundle_add_str(b, "__AUL_SC_APPID__", app_screen->appid);
+       bundle_add_byte(b, "__AUL_SC_PID__", &app_screen->pid, sizeof(int));
+       bundle_add_byte(b, "__AUL_SC_SURFACE__",
+                       &app_screen->surf, sizeof(unsigned int));
+       bundle_add_str(b, "__AUL_SC_INSTANCE_ID__", app_screen->instance_id);
+
+       return b;
+}
+
+static void __send_app_screen_event(struct viewer_info_s *viewer_info,
+               struct app_screen_s *app_screen, const char *event)
+{
+       bundle *b;
+       char endpoint[128];
+
+       b = __create_bundle(app_screen, event);
+       if (b == NULL) {
+               LOGE("out of memory");
+               return;
+       }
+
+       snprintf(endpoint, sizeof(endpoint), "app_screen_event:%u:%d",
+                       viewer_info->ref, viewer_info->pid);
+       amd_app_com_send(endpoint, app_screen->pid, b, app_screen->uid);
+       bundle_free(b);
+}
+
+static void __send_app_screen_added(gpointer data, gpointer user_data)
+{
+       struct viewer_info_s *viewer_info = (struct viewer_info_s *)data;
+       struct app_screen_s *app_screen = (struct app_screen_s *)user_data;
+
+       if (viewer_info->pid == app_screen->pid)
+               return;
+       if (viewer_info->priv && viewer_info->pid != app_screen->caller_pid)
+               return;
+       if (!(viewer_info->screen_type & app_screen->screen_type))
+               return;
+       __send_app_screen_event(viewer_info, app_screen, "add_screen");
+}
+
+static void __send_app_screen_removed(gpointer data, gpointer user_data)
+{
+       struct viewer_info_s *viewer_info = (struct viewer_info_s *)data;
+       struct app_screen_s *app_screen = (struct app_screen_s *)user_data;
+
+       if (viewer_info->pid == app_screen->pid)
+               return;
+       if (viewer_info->priv && viewer_info->pid != app_screen->caller_pid)
+               return;
+       if (!(viewer_info->screen_type & app_screen->screen_type))
+               return;
+       __send_app_screen_event(viewer_info, app_screen, "remove_screen");
+}
+
+static void __send_app_screen_updated(gpointer data, gpointer user_data)
+{
+       struct viewer_info_s *viewer_info = (struct viewer_info_s *)data;
+       struct app_screen_s *app_screen = (struct app_screen_s *)user_data;
+
+       if (viewer_info->pid == app_screen->pid)
+               return;
+       if (viewer_info->priv && viewer_info->pid != app_screen->caller_pid)
+               return;
+       if (!(viewer_info->screen_type & app_screen->screen_type))
+               return;
+       __send_app_screen_event(viewer_info, app_screen, "update_screen");
+}
+
+static int __get_screen_type(int app_type)
+{
+       switch (app_type) {
+       case AMD_AT_UI_APP:
+               return AUL_SCREEN_TYPE_UI;
+       case AMD_AT_WIDGET_APP:
+               return AUL_SCREEN_TYPE_WIDGET;
+       case AMD_AT_WATCH_APP:
+               return AUL_SCREEN_TYPE_WATCH;
+       default:
+               return -1;
+       }
+}
+
+static int __get_pid_by_surf(int pid, unsigned int surf)
+{
+       int *pids = NULL;
+       int cnt = 0;
+       int i;
+       unsigned int wid;
+       app_group_h h;
+
+       _app_group_get_group_pids(pid, &cnt, &pids);
+       for (i = 0; i < cnt; ++i) {
+               h = _app_group_find(pids[i]);
+               wid = (unsigned int)_app_group_get_window(h);
+               if (wid == surf) {
+                       LOGD("pid(%d), surf(%u)", pids[i], surf);
+                       pid = pids[i];
+               }
+       }
+       free(pids);
+
+       return pid;
+}
+
+static gboolean __suspend_timer(gpointer data)
+{
+       int pid = GPOINTER_TO_INT(data);
+       int ret;
+
+       if (pid < 1)
+               return FALSE;
+
+       ret = amd_suspend_update_status(pid, AMD_SUSPEND_STATUS_INCLUDE);
+       LOGD("pid(%d), result(%d)", pid, ret);
+
+       return FALSE;
+}
+
+static int __screen_connector_send_update_request(const char *appid,
+               const char *instance_id, uid_t uid)
+{
+       amd_app_status_h app_status;
+       struct user_info_s *user_info;
+       struct app_screen_s *app_screen;
+       int dummy = 0;
+       int pid;
+       int ret;
+       GList *found;
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info == NULL)
+               return -1;
+
+       if (instance_id) {
+               app_status = amd_app_status_find_by_instance_id(appid,
+                               instance_id, uid);
+       } else {
+               app_status = amd_app_status_find_by_appid(appid, uid);
+       }
+       if (app_status == NULL)
+               return -1;
+       if (amd_app_status_get_status(app_status) == STATUS_DYING)
+               return -1;
+       if (amd_app_status_get_app_type(app_status) != AMD_AT_UI_APP)
+               return -1;
+       if (amd_app_status_is_home_app(app_status))
+               return -1;
+       if (instance_id == NULL) {
+               instance_id = amd_app_status_get_instance_id(app_status);
+               if (instance_id == NULL)
+                       return -1;
+       }
+
+       found = g_list_find_custom(user_info->app_screen_list, instance_id,
+                       __compare_instance_id);
+       if (found == NULL)
+               return -1;
+
+       app_screen = (struct app_screen_s *)found->data;
+       pid = __get_pid_by_surf(app_screen->pid, app_screen->surf);
+       ret = amd_suspend_update_status(pid, AMD_SUSPEND_STATUS_EXCLUDE);
+       if (ret < 0)
+               return -1;
+
+       ret = aul_sock_send_raw(pid, uid, APP_UPDATE_REQUESTED,
+                       (unsigned char *)&dummy, 0, AUL_SOCK_NOREPLY);
+       if (ret < 0) {
+               LOGE("Failed to send the update request");
+               amd_suspend_update_status(pid, AMD_SUSPEND_STATUS_INCLUDE);
+               return -1;
+       }
+       g_timeout_add_seconds(SUSPEND_INTERVAL, __suspend_timer,
+                       GINT_TO_POINTER(pid));
+       LOGD("pid(%d), uid(%d)", pid, uid);
+
+       return 0;
+}
+
+int _screen_connector_add_app_screen(int pid, unsigned int surf,
+               const char *instance_id, uid_t uid)
+{
+       amd_app_status_h app_status;
+       const char *appid;
+       struct user_info_s *user_info;
+       struct app_screen_s *app_screen;
+       int caller_pid;
+       int leader_pid;
+       int app_type;
+       int screen_type;
+       GList *found;
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info == NULL)
+               return -1;
+
+       leader_pid = _app_group_get_leader_pid(_app_group_find(pid));
+       if (leader_pid > 0)
+               pid = leader_pid;
+
+       app_status = amd_app_status_find_by_effective_pid(pid);
+       if (app_status == NULL) {
+               LOGW("Failed to find app status info - pid(%d), uid(%d)",
+                               pid, uid);
+               return -1;
+       }
+
+       if (amd_app_status_is_home_app(app_status))
+               return 0;
+
+       appid = amd_app_status_get_appid(app_status);
+       if (instance_id == NULL) {
+               instance_id = amd_app_status_get_instance_id(app_status);
+               if (instance_id == NULL)
+                       return -1;
+       }
+
+       found = g_list_find_custom(user_info->app_screen_list, instance_id,
+                       __compare_instance_id);
+       if (found) {
+               app_screen = (struct app_screen_s *)found->data;
+               if (app_screen->surf == surf) {
+                       LOGD("Already exists");
+                       return 0;
+               }
+
+               app_screen->surf = surf;
+               g_list_foreach(user_info->screen_viewer_list,
+                               __send_app_screen_updated, app_screen);
+               return 0;
+       }
+
+       caller_pid = amd_app_status_get_first_caller_pid(app_status);
+       app_type = amd_app_status_get_app_type(app_status);
+       screen_type = __get_screen_type(app_type);
+       app_screen = __create_app_screen(pid, uid, appid, surf, instance_id,
+                       screen_type, caller_pid);
+       if (app_screen == NULL)
+               return -1;
+
+       user_info->app_screen_list = g_list_append(user_info->app_screen_list,
+                       app_screen);
+       g_list_foreach(user_info->screen_viewer_list,
+                       __send_app_screen_added, app_screen);
+       LOGD("pid(%d), appid(%s), surf(%d), uid(%d)", pid, appid, surf, uid);
+
+       return 0;
+}
+
+static int __screen_connector_remove_app_screen(int pid, const char *instance_id,
+               uid_t uid)
+{
+       struct user_info_s *user_info;
+       struct app_screen_s *app_screen;
+       amd_app_status_h app_status;
+       int leader_pid;
+       GList *found;
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info == NULL)
+               return -1;
+
+       leader_pid = _app_group_get_leader_pid(_app_group_find(pid));
+       if (leader_pid > 0)
+               pid = leader_pid;
+
+       app_status = amd_app_status_find_by_pid(pid);
+       if (app_status == NULL) {
+               LOGW("Failed to find app status info - pid(%d), uid(%d)",
+                               pid, uid);
+               return -1;
+       }
+
+       if (amd_app_status_is_home_app(app_status))
+               return 0;
+
+       if (instance_id == NULL) {
+               instance_id = amd_app_status_get_instance_id(app_status);
+               if (instance_id == NULL)
+                       return -1;
+       }
+
+       found = g_list_find_custom(user_info->app_screen_list, instance_id,
+                       __compare_instance_id);
+       if (found == NULL)
+               return -1;
+
+       app_screen = (struct app_screen_s *)found->data;
+       g_list_foreach(user_info->screen_viewer_list,
+                       __send_app_screen_removed, app_screen);
+       user_info->app_screen_list = g_list_remove(user_info->app_screen_list,
+                       app_screen);
+       __destroy_app_screen(app_screen);
+       LOGD("pid(%d), instance_id(%s)", pid, instance_id);
+
+       return 0;
+}
+
+static gint __compare_viewers(gconstpointer a, gconstpointer b)
+{
+       struct viewer_info_s *viewer_a = (struct viewer_info_s *)a;
+       struct viewer_info_s *viewer_b = (struct viewer_info_s *)b;
+
+       if (viewer_a->pid == viewer_b->pid &&
+                       viewer_a->screen_type == viewer_b->screen_type &&
+                       viewer_a->priv == viewer_b->priv &&
+                       viewer_a->ref == viewer_b->ref)
+               return 0;
+
+       return -1;
+}
+
+static int __screen_connector_update_app_screen(int pid, uid_t uid)
+{
+       amd_app_status_h app_status;
+       struct user_info_s *user_info;
+       struct app_screen_s *app_screen;
+       const char *appid;
+       const char *instance_id;
+       int leader_pid;
+       GList *found;
+       app_group_h app_group =  _app_group_find(pid);
+       unsigned int surf = (unsigned int)_app_group_get_window(app_group);
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info == NULL)
+               return -1;
+
+       leader_pid = _app_group_get_leader_pid(_app_group_find(pid));
+       if (leader_pid > 0)
+               pid = leader_pid;
+
+       app_status = amd_app_status_find_by_pid(pid);
+       if (app_status == NULL) {
+               LOGW("Failed to find app status info - pid(%d), uid(%d)",
+                               pid, uid);
+               return -1;
+       }
+
+       if (amd_app_status_is_home_app(app_status))
+               return 0;
+
+       appid = amd_app_status_get_appid(app_status);
+       instance_id = amd_app_status_get_instance_id(app_status);
+       if (instance_id == NULL)
+               return -1;
+
+       found = g_list_find_custom(user_info->app_screen_list, instance_id,
+                       __compare_instance_id);
+       if (found == NULL)
+               return -1;
+
+       app_screen = (struct app_screen_s *)found->data;
+       if (app_screen->surf == surf)
+               return 0;
+
+       app_screen->surf = surf;
+       g_list_foreach(user_info->screen_viewer_list,
+                       __send_app_screen_updated, app_screen);
+       LOGD("pid(%d), appid(%s), surf(%d), uid(%d)", pid, appid, surf, uid);
+
+       return 0;
+}
+
+static int __screen_connector_remove_app_screen_v2(int pid, uid_t uid)
+{
+       struct user_info_s *user_info;
+       struct app_screen_s *app_screen;
+       GList *iter;
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info == NULL)
+               return -1;
+
+       iter = g_list_first(user_info->app_screen_list);
+       while (iter) {
+               app_screen = (struct app_screen_s *)iter->data;
+               iter = g_list_next(iter);
+               if (app_screen && app_screen->pid == pid) {
+                       LOGD("pid(%d), surf(%d)", pid, app_screen->surf);
+                       g_list_foreach(user_info->screen_viewer_list,
+                                       __send_app_screen_removed, app_screen);
+                       user_info->app_screen_list = g_list_remove(
+                                       user_info->app_screen_list,
+                                       app_screen);
+                       __destroy_app_screen(app_screen);
+               }
+       }
+
+       return 0;
+}
+
+static void __foreach_app_screen_list(gpointer data, gpointer user_data)
+{
+       __send_app_screen_added(user_data, data);
+}
+
+static int __screen_connector_add_screen_viewer(int pid, int screen_type,
+               bool priv, unsigned int ref, uid_t uid)
+{
+       amd_app_status_h app_status;
+       struct user_info_s *user_info;
+       struct viewer_info_s *viewer_info;
+       GList *list;
+
+       app_status = amd_app_status_find_by_pid(pid);
+       if (app_status == NULL) {
+               LOGW("Failed to find app status info - pid(%d)", pid);
+               return -1;
+       }
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info == NULL) {
+               LOGW("user info is empty");
+               return -1;
+       }
+
+       viewer_info = __create_viewer_info(pid, screen_type, priv, ref);
+       if (viewer_info == NULL)
+               return -1;
+
+       list = g_list_find_custom(user_info->screen_viewer_list, viewer_info,
+                       __compare_viewers);
+       if (list) {
+               LOGD("Already exists");
+               free(viewer_info);
+               return 0;
+       }
+
+       user_info->screen_viewer_list = g_list_append(
+                       user_info->screen_viewer_list, viewer_info);
+
+       g_list_foreach(user_info->app_screen_list,
+                       __foreach_app_screen_list, viewer_info);
+       LOGD("pid(%d), screen_type(%d), private(%d), ref(%u), uid(%d)",
+                       pid, screen_type, priv, ref, uid);
+
+       return 0;
+}
+
+static int __screen_connector_remove_screen_viewer(int pid, int screen_type,
+               bool priv, unsigned int ref, uid_t uid)
+{
+       struct user_info_s *user_info;
+       struct viewer_info_s *viewer_info;
+       GList *iter;
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info == NULL) {
+               LOGW("user info is empty");
+               return -1;
+       }
+
+       iter = g_list_first(user_info->screen_viewer_list);
+       while (iter) {
+               viewer_info = (struct viewer_info_s *)iter->data;
+               iter = g_list_next(iter);
+               if (viewer_info->pid == pid &&
+                               viewer_info->screen_type == screen_type &&
+                               viewer_info->priv == priv &&
+                               viewer_info->ref == ref) {
+                       user_info->screen_viewer_list = g_list_remove(
+                                       user_info->screen_viewer_list,
+                                       viewer_info);
+                       free(viewer_info);
+               }
+       }
+
+       LOGD("pid(%d), screen_type(%d), private(%d), ref(%u) uid(%d)",
+                       pid, screen_type, priv, ref, uid);
+
+       return 0;
+}
+
+static int __screen_connector_remove_screen_viewer_v2(int pid, uid_t uid)
+{
+       struct user_info_s *user_info;
+       struct viewer_info_s *viewer_info;
+       GList *iter;
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info == NULL) {
+               LOGW("user info is empty");
+               return -1;
+       }
+
+       iter = g_list_first(user_info->screen_viewer_list);
+       while (iter) {
+               viewer_info = (struct viewer_info_s *)iter->data;
+               iter = g_list_next(iter);
+               if (viewer_info->pid == pid) {
+                       user_info->screen_viewer_list = g_list_remove(
+                                       user_info->screen_viewer_list,
+                                       viewer_info);
+                       free(viewer_info);
+               }
+       }
+
+       return 0;
+}
+
+static int __screen_connector_usr_init(uid_t uid)
+{
+       struct user_info_s *user_info;
+
+       user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+       if (user_info) {
+               LOGE("Already exists");
+               return 0;
+       }
+
+       user_info = __create_user_info(uid);
+       if (user_info == NULL)
+               return -1;
+
+       g_hash_table_insert(user_table, GUINT_TO_POINTER(uid), user_info);
+
+       return 0;
+}
+
+static void __screen_connector_usr_fini(uid_t uid)
+{
+       g_hash_table_remove(user_table, GUINT_TO_POINTER(uid));
+}
+
+static int __dispatch_add_app_screen(amd_request_h req)
+{
+       uid_t uid = amd_request_get_target_uid(req);
+       int pid = amd_request_get_pid(req);
+       bundle *b = amd_request_get_bundle(req);
+       const char *instance_id;
+       const char *value;
+       unsigned int surf;
+       int ret;
+
+       if (b == NULL)
+               return -1;
+
+       instance_id = bundle_get_val(b, AUL_K_INSTANCE_ID);
+       value = bundle_get_val(b, AUL_K_WID);
+       if (value == NULL)
+               return -1;
+
+       surf = atol(value);
+       ret = _screen_connector_add_app_screen(pid, surf,
+                       instance_id, uid);
+       LOGD("pid(%d), surf(%d), instance_id(%s), result(%d)",
+                       pid, surf, instance_id, ret);
+
+       return 0;
+}
+
+static int __dispatch_remove_app_screen(amd_request_h req)
+{
+       uid_t uid = amd_request_get_target_uid(req);
+       int pid = amd_request_get_pid(req);
+       bundle *b = amd_request_get_bundle(req);
+       const char *instance_id;
+       int ret;
+
+       if (b == NULL)
+               return -1;
+
+       instance_id = bundle_get_val(b, AUL_K_INSTANCE_ID);
+       ret = __screen_connector_remove_app_screen(pid,
+                       instance_id, uid);
+       LOGD("pid(%d), instance_id(%s), result(%d)",
+                       pid, instance_id, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_update_requested(amd_request_h req)
+{
+       uid_t uid = amd_request_get_target_uid(req);
+       int caller_pid = amd_request_get_pid(req);
+       bundle *b = amd_request_get_bundle(req);
+       const char *appid;
+       const char *instance_id;
+       int ret;
+
+       if (b == NULL)
+               return -1;
+
+       appid = bundle_get_val(b, AUL_K_APPID);
+       if (appid == NULL)
+               return -1;
+
+       instance_id = bundle_get_val(b, AUL_K_INSTANCE_ID);
+       ret = __screen_connector_send_update_request(appid, instance_id, uid);
+       LOGD("appid(%s), instance_id(%s), caller_pid(%d), result(%d)",
+                       appid, instance_id, caller_pid, ret);
+
+       return 0;
+}
+
+static int __dispatch_add_screen_viewer(amd_request_h req)
+{
+       uid_t uid = amd_request_get_target_uid(req);
+       int pid = amd_request_get_pid(req);
+       bundle *b = amd_request_get_bundle(req);
+       const char *value;
+       bool priv;
+       int screen_type;
+       unsigned int ref;
+       int ret;
+
+       if (b == NULL)
+               return -1;
+
+       value = bundle_get_val(b, AUL_K_SCREEN_TYPE);
+       if (value == NULL)
+               return -1;
+       screen_type = atoi(value);
+
+       value = bundle_get_val(b, AUL_K_VIEWER_REF);
+       if (value == NULL)
+               return -1;
+       ref = atol(value);
+
+       value = bundle_get_val(b, AUL_K_PRIVATE);
+       if (value && strcmp(value, "true") == 0)
+               priv = true;
+       else
+               priv = false;
+
+       ret = __screen_connector_add_screen_viewer(pid, screen_type,
+                       priv, ref, uid);
+       LOGD("pid(%d), screen_type(%d), private(%d), result(%d)",
+                       pid, screen_type, priv, ret);
+
+       return 0;
+}
+
+static int __dispatch_remove_screen_viewer(amd_request_h req)
+{
+       uid_t uid = amd_request_get_target_uid(req);
+       int pid = amd_request_get_pid(req);
+       bundle *b = amd_request_get_bundle(req);
+       const char *value;
+       bool priv;
+       int screen_type;
+       unsigned int ref;
+       int ret;
+
+       if (b == NULL)
+               return -1;
+
+       value = bundle_get_val(b, AUL_K_SCREEN_TYPE);
+       if (value == NULL)
+               return -1;
+       screen_type = atoi(value);
+
+       value = bundle_get_val(b, AUL_K_VIEWER_REF);
+       if (value == NULL)
+               return -1;
+       ref = atol(value);
+
+       value = bundle_get_val(b, AUL_K_PRIVATE);
+       if (value && strcmp(value, "true") == 0)
+               priv = true;
+       else
+               priv = false;
+
+       ret = __screen_connector_remove_screen_viewer(pid, screen_type,
+                       priv, ref, uid);
+       LOGD("pid(%d), screen_type(%d), private(%d), result(%d)",
+                       pid, screen_type, priv, ret);
+
+       return 0;
+}
+
+static int __screen_connector_checker(amd_cynara_caller_info_h info, amd_request_h req,
+               void *data)
+{
+       int ret;
+       bundle *b = amd_request_get_bundle(req);
+       const char *type_str;
+       int type;
+
+       if (b == NULL)
+               return -1;
+
+       type_str = bundle_get_val(b, AUL_K_SCREEN_TYPE);
+       if (type_str == NULL)
+               return -1;
+
+       type = atoi(type_str);
+       if (type & AUL_SCREEN_TYPE_UI)
+               ret = amd_cynara_simple_checker(info, req, PRIVILEGE_PLATFORM);
+       else
+               ret = amd_cynara_simple_checker(info, req, PRIVILEGE_WIDGET_VIEWER);
+
+       return ret;
+}
+
+static amd_request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = ADD_APP_SCREEN,
+               .callback = __dispatch_add_app_screen
+       },
+       {
+               .cmd = REMOVE_APP_SCREEN,
+               .callback = __dispatch_remove_app_screen
+       },
+       {
+               .cmd = APP_UPDATE_REQUESTED,
+               .callback = __dispatch_app_update_requested
+       },
+       {
+               .cmd = ADD_SCREEN_VIEWER,
+               .callback = __dispatch_add_screen_viewer
+       },
+       {
+               .cmd = REMOVE_SCREEN_VIEWER,
+               .callback = __dispatch_remove_screen_viewer
+       },
+};
+
+static amd_cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = ADD_SCREEN_VIEWER,
+               .checker = __screen_connector_checker,
+               .data = NULL
+       },
+       {
+               .cmd = REMOVE_SCREEN_VIEWER,
+               .checker = __screen_connector_checker,
+               .data = NULL
+       },
+       {
+               .cmd = APP_UPDATE_REQUESTED,
+               .checker = amd_cynara_simple_checker,
+               .data = PRIVILEGE_PLATFORM
+       },
+};
+
+static int __on_launch_status(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       uid_t uid = arg2;
+
+       __screen_connector_update_app_screen(pid, uid);
+
+       return 0;
+}
+
+static int __on_app_status_end(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_app_status_h h = arg3;
+
+       if (amd_app_status_get_status(h) == STATUS_DYING) {
+               __screen_connector_remove_app_screen_v2(amd_app_status_get_pid(h),
+                               amd_app_status_get_uid(h));
+       }
+
+       return 0;
+}
+
+static int __on_app_status_cleanup(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       int pid = arg1;
+       uid_t uid = arg2;
+
+       __screen_connector_remove_app_screen_v2(pid, uid);
+       __screen_connector_remove_screen_viewer_v2(pid, uid);
+
+       return 0;
+}
+
+static int __on_login(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       uid_t uid = arg1;
+       int status = arg2;
+
+       if (status & (AMD_UID_STATE_OPENING | AMD_UID_STATE_ONLINE |
+                       AMD_UID_STATE_ACTIVE))
+               __screen_connector_usr_init(uid);
+
+       return 0;
+}
+
+static int __on_logout(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       uid_t uid = arg1;
+       int status = arg2;
+
+       if (status & (AMD_UID_STATE_CLOSING | AMD_UID_STATE_OFFLINE))
+               __screen_connector_usr_fini(uid);
+
+       return 0;
+}
+
+int _screen_connector_init(void)
+{
+       int r;
+
+       LOGD("screen connector init");
+
+       user_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                       NULL, __destroy_user_info);
+       if (user_table == NULL) {
+               LOGE("Failed to create user table");
+               return -1;
+       }
+
+       r = amd_request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               LOGE("Failed to register cmds");
+               return -1;
+       }
+
+       r = amd_cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (r < 0) {
+               LOGE("Failed to register checkers");
+               return -1;
+       }
+
+       amd_noti_listen("launch.status.fg", __on_launch_status);
+       amd_noti_listen("launch.status.focus", __on_launch_status);
+       amd_noti_listen("app_status.update_status.end", __on_app_status_end);
+       amd_noti_listen("app_status.cleanup", __on_app_status_cleanup);
+       amd_noti_listen("login_monitor.login", __on_login);
+       amd_noti_listen("login_monitor.logout", __on_logout);
+
+       return 0;
+}
+
+void _screen_connector_fini(void)
+{
+       LOGD("screen connector fini");
+
+       if (user_table)
+               g_hash_table_destroy(user_table);
+}
diff --git a/modules/ui-core/src/ui_core.c b/modules/ui-core/src/ui_core.c
new file mode 100644 (file)
index 0000000..57e433a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <dlog.h>
+
+#include "amd.h"
+#include "amd_screen_connector.h"
+#include "amd_app_group.h"
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_UI_CORE"
+
+#undef EXPORT
+#define EXPORT __attribute__ ((visibility("default")))
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       LOGD("ui-core init");
+       if (_app_group_init() < 0)
+               return -1;
+
+       if (_screen_connector_init() < 0)
+               return -1;
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       LOGD("ui-core fini");
+       _screen_connector_fini();
+       _app_group_fini();
+}
+
diff --git a/modules/wayland-core/CMakeLists.txt b/modules/wayland-core/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4fe94b1
--- /dev/null
@@ -0,0 +1,44 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_WAYLAND_CORE "amd-mod-wayland-core")
+SET(AMD_MOD_WAYLAND_CORE_DIR ${CMAKE_SOURCE_DIR}/modules/wayland-core)
+PROJECT(${AMD_MOD_WAYLAND_CORE} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_WAYLAND_CORE_DIR}/src AMD_MOD_WAYLAND_CORE_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_WAYLAND_CORE_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       wayland-client
+       wayland-tbm-client
+       tizen-extension-client
+       )
+
+pkg_check_modules(amd_mod_wayland_core_pkgs REQUIRED ${AMD_MOD_WAYLAND_CORE_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_wayland_core_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_WAYLAND_CORE_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_WAYLAND_CORE} ${AMD_MOD_WAYLAND_CORE_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_WAYLAND_CORE} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_WAYLAND_CORE} ${amd_mod_wayland_core_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_WAYLAND_CORE} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/wayland-core/inc/wayland-core-private.h b/modules/wayland-core/inc/wayland-core-private.h
new file mode 100644 (file)
index 0000000..df835ff
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_WAYLAND_CORE"
+
+#undef EXPORT
+#define EXPORT __attribute__ ((visibility("default")))
diff --git a/modules/wayland-core/src/wayland-core.c b/modules/wayland-core/src/wayland-core.c
new file mode 100644 (file)
index 0000000..561979c
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <wayland-client.h>
+#include <wayland-tbm-client.h>
+#include <tizen-extension-client-protocol.h>
+#include <amd.h>
+
+#include "wayland-core-private.h"
+
+#define PATH_RUN_WAYLAND "/run/wayland-0"
+#define PATH_RUN_WMREADY "/run/.wm_ready"
+#define PATH_RUN "/run"
+
+static bool wl_ready;
+static bool wm_ready;
+static bool wl_initialized;
+static struct wl_display *display;
+static struct wl_registry *registry;
+static guint sid;
+static int __wd;
+
+static void __wl_listener_cb(void *data, struct wl_registry *reg,
+               unsigned int id, const char *interface, unsigned int version)
+{
+       char buf[512];
+
+       if (!interface)
+               return;
+
+       snprintf(buf, sizeof(buf), "wayland.listener.%s", interface);
+       amd_noti_send(buf, (int)id, (int)version, reg, NULL);
+}
+
+static void __wl_listener_remove_cb(void *data, struct wl_registry *reg,
+               unsigned int id)
+{
+       amd_noti_send("wayland.listener_remove", (int)id, 0, reg, NULL);
+}
+
+
+static const struct wl_registry_listener registry_listener = {
+       __wl_listener_cb,
+       __wl_listener_remove_cb
+};
+
+static gboolean __init_wl(gpointer data)
+{
+       display = wl_display_connect(NULL);
+       if (display == NULL) {
+               LOGE("Failed to connect wayland display");
+               sid = 0;
+               return G_SOURCE_REMOVE;
+       }
+
+       registry = wl_display_get_registry(display);
+       if (registry == NULL) {
+               LOGE("Failed to get wayland registry");
+               wl_display_disconnect(display);
+               display = NULL;
+               sid = 0;
+               return G_SOURCE_REMOVE;
+       }
+
+       wl_registry_add_listener(registry, &registry_listener, NULL);
+       wl_display_flush(display);
+       wl_display_roundtrip(display);
+
+       amd_wayland_set_display(display);
+       sid = 0;
+
+       return G_SOURCE_REMOVE;
+}
+
+static bool __wayland_monitor_cb(const char *event_name, void *data)
+{
+       if (event_name == NULL)
+               return true;
+
+       if (strcmp(event_name, "wayland-0") == 0) {
+               LOGD("%s is created", event_name);
+               wl_ready = true;
+       } else if (strcmp(event_name, ".wm_ready") == 0) {
+               LOGD("%s is created", event_name);
+               wm_ready = true;
+       }
+
+       if (wm_ready && wl_ready) {
+               wl_initialized = true;
+               sid = g_idle_add(__init_wl, NULL);
+               __wd = 0;
+               return false;
+       }
+
+       return true;
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       LOGD("wayland core init");
+
+       if (access(PATH_RUN_WAYLAND, F_OK) == 0) {
+               LOGD("%s exists", PATH_RUN_WAYLAND);
+               wl_ready = true;
+       }
+
+       if (access(PATH_RUN_WMREADY, F_OK) == 0) {
+               LOGD("%s exists", PATH_RUN_WMREADY);
+               wm_ready = true;
+       }
+
+       if (wl_ready && wm_ready) {
+               wl_initialized = true;
+               sid = g_idle_add(__init_wl, NULL);
+               return 0;
+       }
+
+       __wd = amd_inotify_add_watch(PATH_RUN, IN_CREATE,
+                       __wayland_monitor_cb, NULL);
+       if (__wd < 0) {
+               LOGE("Failed to add inotify watch");
+               return -1;
+       }
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       LOGD("wayland core finish");
+
+       if (__wd > 0)
+               amd_inotify_rm_watch(__wd);
+
+       if (sid) {
+               g_source_remove(sid);
+               sid = 0;
+       }
+
+       if (registry) {
+               wl_registry_destroy(registry);
+               registry = NULL;
+       }
+
+       if (display) {
+               wl_display_disconnect(display);
+               display = NULL;
+       }
+}
diff --git a/modules/widget/CMakeLists.txt b/modules/widget/CMakeLists.txt
new file mode 100644 (file)
index 0000000..783b728
--- /dev/null
@@ -0,0 +1,43 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+SET(AMD_MOD_WIDGET "amd-mod-widget")
+SET(AMD_MOD_WIDGET_DIR ${CMAKE_SOURCE_DIR}/modules/widget)
+PROJECT(${AMD_MOD_WIDGET} C)
+AUX_SOURCE_DIRECTORY(${AMD_MOD_WIDGET_DIR}/src AMD_MOD_WIDGET_SOURCES)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_MOD_WIDGET_PKG_CHECK_MODULES
+       dlog
+       glib-2.0
+       gio-2.0
+       aul
+       bundle
+       )
+
+pkg_check_modules(amd_mod_widget_pkgs REQUIRED ${AMD_MOD_WIDGET_PKG_CHECK_MODULES})
+
+FOREACH(flag ${amd_mod_widget_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${AMD_MOD_WIDGET_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-pie -Wl,--as-needed")
+
+ADD_LIBRARY(${AMD_MOD_WIDGET} ${AMD_MOD_WIDGET_SOURCES})
+SET_TARGET_PROPERTIES(${AMD_MOD_WIDGET} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${AMD_MOD_WIDGET} ${amd_mod_widget_pkgs_LDFLAGS} libamd)
+
+INSTALL(TARGETS ${AMD_MOD_WIDGET} DESTINATION ${AMD_MODULES_DIR}/mod COMPONENT RuntimeLibraries)
diff --git a/modules/widget/inc/amd_widget.h b/modules/widget/inc/amd_widget.h
new file mode 100644 (file)
index 0000000..3592368
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_WIDGET"
+
+#undef EXPORT
+#define EXPORT __attribute__ ((visibility("default")))
+
diff --git a/modules/widget/src/amd_widget.c b/modules/widget/src/amd_widget.c
new file mode 100644 (file)
index 0000000..ad67a1b
--- /dev/null
@@ -0,0 +1,972 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <aul.h>
+#include <aul_svc.h>
+#include <aul_svc_priv_key.h>
+#include <aul_sock.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+
+#include "amd.h"
+#include "amd_widget.h"
+
+#ifndef AUL_K_WIDGET_OPERATION
+#define AUL_K_WIDGET_OPERATION "__WIDGET_OP__"
+#endif
+#define MAX_NR_OF_DESCRIPTORS 2
+#define MAX_PID_STR_BUFSZ 20
+#define REGULAR_UID_MIN 5000
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+typedef struct _widget_t {
+       char *widget_id;
+       int pid;
+       uid_t uid;
+       bool is_dying;
+       GList *instances;
+} widget_t;
+
+static GList *__widgets;
+
+static void __free_widget(gpointer data)
+{
+       widget_t *widget = (widget_t *)data;
+
+       free(widget->widget_id);
+       g_list_free_full(widget->instances, free);
+       free(widget);
+}
+
+static widget_t *__find_widget(const char *widget_id, int pid, uid_t uid)
+{
+       GList *widget_list = __widgets;
+       widget_t *widget;
+
+       while (widget_list) {
+               widget = (widget_t *)widget_list->data;
+               if (strcmp(widget->widget_id, widget_id) == 0) {
+                       if (widget->pid == pid && widget->uid == uid)
+                               return widget;
+               }
+
+               widget_list = widget_list->next;
+       }
+
+       return NULL;
+}
+
+static widget_t *__find_instance(const char *widget_id, const char *instance_id)
+{
+       GList *widget_list = __widgets;
+       GList *instance_list;
+       widget_t *widget;
+
+       while (widget_list) {
+               widget = (widget_t *)widget_list->data;
+               if (strcmp(widget->widget_id, widget_id) == 0
+                                               && widget->instances) {
+                       instance_list = g_list_find_custom(widget->instances,
+                                       instance_id, (GCompareFunc)g_strcmp0);
+
+                       if (instance_list)
+                               return widget;
+               }
+
+               widget_list = widget_list->next;
+       }
+
+       return NULL;
+}
+
+static bool __widget_exist(int pid, uid_t uid)
+{
+       GList *widget_list = __widgets;
+       widget_t *widget;
+
+       while (widget_list) {
+               widget = (widget_t *)widget_list->data;
+               if (widget->pid == pid && widget->uid == uid)
+                       return true;
+
+               widget_list = widget_list->next;
+       }
+       return false;
+}
+
+static int __widget_send_dead_signal(int pid, uid_t uid, const char *pkgid)
+{
+       bundle *kb;
+       widget_t *widget = NULL;
+       GList *widget_list = __widgets;
+       int status = AUL_WIDGET_LIFE_CYCLE_EVENT_APP_DEAD;
+       char sender_pid_str[MAX_PID_STR_BUFSZ];
+
+       while (widget_list) {
+               widget = (widget_t *)widget_list->data;
+               if (widget->pid == pid && widget->uid == uid)
+                       break;
+               widget_list = widget_list->next;
+       }
+       if (!widget) {
+               LOGE("cannot find widget pid : %d, uid %d", pid, uid);
+               return -1;
+       }
+       snprintf(sender_pid_str, MAX_PID_STR_BUFSZ, "%d", pid);
+
+       kb = bundle_create();
+       if (!kb) {
+               LOGE("cannot create bundle out of memory");
+               return -1;
+       }
+
+       bundle_add(kb, AUL_K_WIDGET_ID, widget->widget_id);
+       bundle_add_byte(kb, AUL_K_WIDGET_STATUS, &status, sizeof(int));
+       bundle_add(kb, AUL_K_COM_SENDER_PID, sender_pid_str);
+       bundle_add(kb, AUL_K_PKGID, pkgid);
+       if (!widget->is_dying)
+               bundle_add(kb, AUL_K_WIDGET_FAULT, "true");
+       amd_app_com_send("widget.status", getpgid(pid), kb, uid);
+       bundle_free(kb);
+
+       return 0;
+}
+
+static int __widget_add(const char *widget_id, const char *instance_id,
+               int pid, uid_t uid)
+{
+       widget_t *widget;
+       char *id;
+
+       if (!widget_id || !instance_id)
+               return -1;
+
+       id = strdup(instance_id);
+       if (!id) {
+               LOGE("out of memory");
+               return -1;
+       }
+
+       widget = __find_widget(widget_id, pid, uid);
+       if (!widget) {
+               widget = __find_instance(widget_id, instance_id);
+               if (!widget) {
+                       widget = (widget_t *)calloc(1, sizeof(widget_t));
+                       if (!widget) {
+                               LOGE("out of memory");
+                               free(id);
+                               return -1;
+                       }
+                       widget->widget_id = strdup(widget_id);
+                       if (widget->widget_id == NULL) {
+                               LOGE("Out of memory");
+                               free(widget);
+                               free(id);
+                               return -1;
+                       }
+                       widget->uid = uid;
+                       __widgets = g_list_append(__widgets, widget);
+               }
+               widget->pid = pid;
+       }
+       if (__find_instance(widget_id, instance_id) == NULL)
+               widget->instances = g_list_append(widget->instances, id);
+       else
+               free(id);
+
+       LOGD("widget instance added: %s - %s (%d:%d)", widget_id, instance_id,
+                                                               uid, pid);
+       return 0;
+}
+
+static int __widget_del(const char *widget_id, const char *instance_id)
+{
+       widget_t *widget;
+       GList *stored_list;
+
+       if (!widget_id || !instance_id)
+               return -1;
+
+       widget = __find_instance(widget_id, instance_id);
+       if (!widget)
+               return -1;
+       stored_list = g_list_find_custom(widget->instances, instance_id,
+                        (GCompareFunc)g_strcmp0);
+
+       if (stored_list) {
+               widget->instances = g_list_remove_link(widget->instances,
+                               stored_list);
+               free(stored_list->data);
+               g_list_free(stored_list);
+               LOGD("widget instace deleted: %s - %s (%d:%d)", widget->widget_id,
+                               instance_id, widget->uid, widget->pid);
+               return 0;
+       }
+
+       return -1;
+}
+
+static int __widget_list(const char *widget_id, amd_request_h req)
+{
+       bundle *rvalue;
+       widget_t *widget;
+       GList *widget_list = __widgets;
+       GList *instance_list;
+       char pid_buf[10];
+       int fd;
+
+       if (!widget_id)
+               return -1;
+
+       rvalue = bundle_create();
+       if (!rvalue) {
+               LOGE("out of memory");
+               return -1;
+       }
+
+       LOGD("start instance list");
+
+       while (widget_list) {
+               widget = (widget_t *)widget_list->data;
+               if (strcmp(widget->widget_id, widget_id) == 0) {
+                       instance_list = widget->instances;
+                       snprintf(pid_buf, sizeof(pid_buf), "%d", widget->pid);
+                       while (instance_list) {
+                               LOGD("%s - %s", widget_id,
+                                       (const char *)instance_list->data);
+                               bundle_add_str(rvalue, instance_list->data,
+                                                               pid_buf);
+                               instance_list = instance_list->next;
+                       }
+               }
+               widget_list = widget_list->next;
+       }
+
+       LOGD("end instance list");
+
+       fd = amd_request_remove_fd(req);
+       aul_sock_send_bundle_with_fd(fd, 0, rvalue, AUL_SOCK_NOREPLY);
+
+       bundle_free(rvalue);
+
+       return 0;
+}
+
+static int __widget_update(const char *widget_id, amd_request_h req)
+{
+       char *instance_id;
+       char *appid;
+       bundle *kb = amd_request_get_bundle(req);
+       int ret = -1;
+       widget_t *widget;
+       GList *widget_list = __widgets;
+       bool dummy;
+       bool dummy_mode;
+
+       if (!kb || !widget_id) {
+               amd_request_send_result(req, -EINVAL);
+               return -1;
+       }
+
+       bundle_get_str(kb, AUL_K_APPID, &appid);
+       if (!appid) {
+               LOGE("missing appid:%s", widget_id);
+               amd_request_send_result(req, -EINVAL);
+               return -1;
+       }
+
+       bundle_get_str(kb, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
+       if (!instance_id) { /* all instances */
+               while (widget_list) {
+                       widget = (widget_t *)widget_list->data;
+                       if (strcmp(widget->widget_id, widget_id) == 0) {
+                               bundle_del(kb, AUL_K_TARGET_PID);
+                               bundle_add_byte(kb, AUL_K_TARGET_PID,
+                                               (void *)&widget->pid,
+                                               sizeof(widget->pid));
+
+                               ret = amd_launch_start_app(appid, req, &dummy,
+                                               &dummy_mode, false);
+                               LOGD("update widget: %s(%d)", widget->widget_id,
+                                                               widget->pid);
+                       }
+                       widget_list = widget_list->next;
+               }
+       } else {
+               widget = __find_instance(widget_id, instance_id);
+               if (widget) {
+                       bundle_del(kb, AUL_K_TARGET_PID);
+                       bundle_add_byte(kb, AUL_K_TARGET_PID,
+                               (void *)&widget->pid, sizeof(widget->pid));
+               }
+               ret = amd_launch_start_app(appid, req, &dummy, &dummy_mode, false);
+               LOGD("update widget: %s", widget_id);
+       }
+
+       return ret;
+}
+
+static int __widget_cleanup(int pid, uid_t uid)
+{
+       GList *widget_list = __widgets;
+       widget_t *widget;
+
+       while (widget_list) {
+               widget = (widget_t *)widget_list->data;
+               widget_list = widget_list->next;
+               if (widget->pid == pid && widget->uid == uid) {
+                       if (widget->instances)
+                               g_list_free_full(widget->instances, free);
+                       __widgets = g_list_remove(__widgets, widget);
+               }
+       }
+
+       LOGD("cleanup widget %d:%d", pid, uid);
+
+       return 0;
+}
+
+static int __widget_get_pid(const char *widget_id, const char *instance_id)
+{
+       widget_t *widget;
+
+       widget = __find_instance(widget_id, instance_id);
+       if (!widget)
+               return -1;
+
+       return widget->pid;
+}
+
+static int __widget_count(const char *widget_id, uid_t uid)
+{
+       widget_t *widget;
+       GList *widget_list = __widgets;
+       GList *instance_list;
+       int count = 0;
+
+       if (!widget_id)
+               return -1;
+
+       while (widget_list) {
+               widget = (widget_t *)widget_list->data;
+               LOGD("widget %s", widget->widget_id);
+               if (strcmp(widget->widget_id, widget_id) == 0 &&
+                               widget->uid == uid) {
+                       instance_list = widget->instances;
+                       if (instance_list)
+                               count += g_list_length(instance_list);
+                       LOGD("widget count %d", count);
+               }
+               widget_list = widget_list->next;
+       }
+
+       return count;
+}
+
+static int __widget_verify_cmd(amd_request_h req)
+{
+       bundle *kb = amd_request_get_bundle(req);
+       const char *command;
+       const char *instance_id;
+       const char *widget_id;
+       widget_t *widget;
+
+       if (!kb) {
+               LOGE("invalid argument");
+               return -1;
+       }
+
+       widget_id = bundle_get_val(kb, AUL_K_WIDGET_ID);
+       if (!widget_id)
+               return 0;
+
+       instance_id = bundle_get_val(kb, AUL_K_WIDGET_INSTANCE_ID);
+       if (!instance_id)
+               return 0;
+
+       command = bundle_get_val(kb, AUL_K_WIDGET_OPERATION);
+       if (!command)
+               return 0;
+
+       if (strcmp(command, "create") == 0)
+               return 0;
+
+       widget = __find_instance(widget_id, instance_id);
+       if (!widget) {
+               LOGE("invalid command: %s - target instance %s is not exist",
+                       command, instance_id);
+               return -EREJECTED;
+       }
+
+       return 0;
+}
+
+static int __widget_is_dying(int pid, uid_t uid)
+{
+       GList *widget_list = __widgets;
+       widget_t *widget;
+
+       while (widget_list) {
+               widget = (widget_t *)widget_list->data;
+               if (widget->pid == pid && widget->uid == uid) {
+                       widget->is_dying = true;
+                       return 0;
+               }
+
+               widget_list = widget_list->next;
+       }
+
+       return -1;
+}
+
+static int __validate_widget_owner(amd_request_h req)
+{
+       amd_app_status_h status;
+       const char *appid;
+       char *widget_id = NULL;
+       const char *appid_part = NULL;
+       bundle *kb = amd_request_get_bundle(req);
+
+       status = amd_app_status_find_by_pid(amd_request_get_pid(req));
+       if (!status)
+               return -1;
+
+       appid = amd_app_status_get_appid(status);
+       bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+       if (!widget_id || !appid)
+               return -1;
+
+       appid_part = g_strstr_len(widget_id, strlen(widget_id), "@");
+       if (appid_part)
+               appid_part = appid_part + 1;
+       else
+               appid_part = widget_id;
+
+       return strcmp(appid_part, appid);
+}
+
+static int __dispatch_widget_add_del(amd_request_h req)
+{
+       bundle *kb = amd_request_get_bundle(req);
+       char *widget_id = NULL;
+       char *instance_id = NULL;
+       int ret;
+
+       if (__validate_widget_owner(req) < 0) {
+               amd_request_send_result(req, -EINVAL);
+               return -1;
+       }
+
+       bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+       bundle_get_str(kb, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
+       if (!widget_id || !instance_id) {
+               amd_request_send_result(req, -EINVAL);
+               return -1;
+       }
+
+       if (amd_request_get_cmd(req) == WIDGET_ADD) {
+               ret = __widget_add(widget_id, instance_id,
+                               amd_request_get_pid(req), amd_request_get_uid(req));
+       } else {
+               ret = __widget_del(widget_id, instance_id);
+       }
+
+       amd_request_send_result(req, ret);
+
+       return ret;
+}
+
+static int __validate_widget_caller(amd_request_h req)
+{
+       bundle *kb = amd_request_get_bundle(req);
+       char *appid = NULL;
+       amd_appinfo_h target;
+       const char *target_pkgid;
+       amd_app_status_h caller_status;
+       const char *caller_pkgid;
+
+       if (amd_request_get_uid(req) < REGULAR_UID_MIN) {
+               LOGD("bypass caller package check");
+               return 0;
+       }
+
+       bundle_get_str(kb, AUL_K_APPID, &appid);
+       if (!appid) {
+               LOGE("no appid provided");
+               return -1;
+       }
+
+       target = amd_appinfo_find(amd_request_get_uid(req), appid);
+       if (!target) {
+               LOGE("can not find appinfo of %s", appid);
+               return -1;
+       }
+
+       target_pkgid = amd_appinfo_get_value(target, AMD_AIT_PKGID);
+       if (!target_pkgid) {
+               LOGE("can not get pkgid %s", target_pkgid);
+               return -1;
+       }
+
+       caller_status = amd_app_status_find_by_pid(amd_request_get_pid(req));
+       if (!caller_status)
+               return 0; /* not app? */
+
+       caller_pkgid = amd_app_status_get_pkgid(caller_status);
+       if (!caller_pkgid) {
+               LOGE("can not get caller pkgid");
+               return -1;
+       }
+
+       LOGD("compare pkgid %s:%s", caller_pkgid, target_pkgid);
+       if (strcmp(caller_pkgid, target_pkgid) == 0)
+               return 0;
+
+       return -1;
+}
+
+static int __send_message(int sock, const struct iovec *vec, int vec_size,
+               const int *desc, int nr_desc)
+{
+       struct msghdr msg = {0,};
+       int sndret;
+       int desclen = 0;
+       struct cmsghdr *cmsg = NULL;
+       char buff[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS)] = {0,};
+
+       if (vec == NULL || vec_size < 1)
+               return -EINVAL;
+       if (nr_desc < 0 || nr_desc > MAX_NR_OF_DESCRIPTORS)
+               return -EINVAL;
+       if (desc == NULL)
+               nr_desc = 0;
+
+       msg.msg_iov = (struct iovec *)vec;
+       msg.msg_iovlen = vec_size;
+
+       /* sending ancillary data */
+       if (nr_desc > 0) {
+               msg.msg_control = buff;
+               msg.msg_controllen = sizeof(buff);
+               cmsg = CMSG_FIRSTHDR(&msg);
+               if (cmsg == NULL)
+                       return -EINVAL;
+
+               /* packing files descriptors */
+               if (nr_desc > 0) {
+                       cmsg->cmsg_level = SOL_SOCKET;
+                       cmsg->cmsg_type = SCM_RIGHTS;
+                       desclen = cmsg->cmsg_len =
+                               CMSG_LEN(sizeof(int) * nr_desc);
+                       memcpy((int *)CMSG_DATA(cmsg), desc,
+                                       sizeof(int) * nr_desc);
+                       cmsg = CMSG_NXTHDR(&msg, cmsg);
+                       LOGD("packing file descriptors done");
+               }
+
+               /* finished packing updating the corect length */
+               msg.msg_controllen = desclen;
+       } else {
+               msg.msg_control = NULL;
+               msg.msg_controllen = 0;
+       }
+
+       sndret = sendmsg(sock, &msg, 0);
+       LOGD("sendmsg ret : %d", sndret);
+       if (sndret < 0)
+               return -errno;
+
+       return sndret;
+}
+
+static int __dispatch_widget_get_content(amd_request_h req)
+{
+       int handles[2] = {0,};
+       struct iovec vec[3];
+       int msglen = 0;
+       char buffer[1024];
+       int ret;
+       bundle *kb = amd_request_get_bundle(req);
+       struct timeval tv;
+       int pid;
+       char *widget_id = NULL;
+       char *instance_id = NULL;
+
+       if (__validate_widget_caller(req) < 0) {
+               amd_request_send_result(req, -EILLEGALACCESS);
+               return -1;
+       }
+
+       bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+       bundle_get_str(kb, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
+
+       pid = __widget_get_pid(widget_id, instance_id);
+       if (pid < 0) {
+               LOGE("can not find widget");
+               amd_request_send_result(req, -ENOENT);
+               return -1;
+       }
+
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
+               LOGE("error create socket pair");
+               amd_request_send_result(req, -1);
+               return -1;
+       }
+
+       if (handles[0] == -1) {
+               LOGE("error socket open");
+               amd_request_send_result(req, -1);
+               return -1;
+       }
+
+       tv.tv_sec = 5;
+       tv.tv_usec = 0;
+
+       ret = setsockopt(handles[1], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+       if (ret < 0) {
+               LOGE("cannot set SO_RCVTIMEO for socket %d", handles[0]);
+               amd_request_send_result(req, -1);
+               goto out;
+       }
+
+       vec[0].iov_base = buffer;
+       vec[0].iov_len = strlen(buffer) + 1;
+
+       ret = aul_sock_send_bundle(pid, amd_request_get_target_uid(req),
+                       amd_request_get_cmd(req), amd_request_get_bundle(req),
+                       AUL_SOCK_ASYNC);
+
+       msglen = __send_message(ret, vec, 1, &(handles[0]), 1);
+       if (msglen < 0) {
+               LOGE("Error[%d]: while sending message to widget", -msglen);
+               amd_request_send_result(req, -1);
+               ret = -1;
+               goto out;
+       }
+
+       msglen = __send_message(amd_request_get_fd(req), vec, 1, &(handles[1]), 1);
+       if (msglen < 0) {
+               LOGE("Error[%d]: while sending message to caller", -msglen);
+               amd_request_send_result(req, -1);
+               ret = -1;
+       }
+
+out:
+       close(handles[0]);
+       close(handles[1]);
+
+       return ret;
+}
+
+static int __dispatch_widget_list(amd_request_h req)
+{
+       bundle *kb = amd_request_get_bundle(req);
+       char *widget_id = NULL;
+       int ret;
+
+       if (__validate_widget_caller(req) < 0) {
+               amd_request_send_result(req, -EILLEGALACCESS);
+               return -1;
+       }
+
+       bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+       if (!widget_id) {
+               amd_request_send_result(req, -EINVAL);
+               return -1;
+       }
+
+       ret = __widget_list(widget_id, req);
+
+       return ret;
+}
+
+static int __dispatch_widget_update(amd_request_h req)
+{
+       bundle *kb = amd_request_get_bundle(req);
+       char *widget_id = NULL;
+       int ret;
+
+       if (__validate_widget_caller(req) < 0) {
+               amd_request_send_result(req, -EILLEGALACCESS);
+               return -1;
+       }
+
+       bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+       if (!widget_id) {
+               amd_request_send_result(req, -EINVAL);
+               return -1;
+       }
+
+       /* update will pass bundle by app_control */
+       amd_request_set_cmd(req, APP_START_ASYNC);
+
+       ret = __widget_update(widget_id, req);
+       if (ret < 0)
+               return -1;
+
+       return 0;
+}
+
+static int __dispatch_widget_count(amd_request_h req)
+{
+       bundle *kb = amd_request_get_bundle(req);
+       char *widget_id = NULL;
+       int count;
+
+       bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+       if (!widget_id) {
+               amd_request_send_result(req, -EINVAL);
+               return -1;
+       }
+       count = __widget_count(widget_id, amd_request_get_uid(req));
+       LOGD("dispatch widget count %d", count);
+       amd_request_send_result(req, count);
+
+       return 0;
+}
+
+static int __dispatch_widget_notify_exit(amd_request_h req)
+{
+       int pid = amd_request_get_pid(req);
+       uid_t uid = amd_request_get_uid(req);
+       int ret;
+
+       ret = __widget_is_dying(pid, uid);
+       LOGD("[WIDGET_NOTIFY_EXIT] result(%d)", ret);
+
+       return 0;
+}
+
+static int __app_term_by_pid_async_checker(amd_cynara_caller_info_h info,
+               amd_request_h req, void *data)
+{
+       int pid;
+       char *term_pid;
+       bundle *kb;
+       amd_app_status_h status;
+       amd_appinfo_h ai;
+       const char *comp_type;
+
+       kb = amd_request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       bundle_get_str(kb, AUL_K_APPID, &term_pid);
+       if (term_pid == NULL)
+               return -1;
+
+       pid = atoi(term_pid);
+       status = amd_app_status_find_by_pid(pid);
+       if (!status)
+               return -1;
+
+       ai = amd_appinfo_find(amd_request_get_target_uid(req), amd_app_status_get_appid(status));
+       if (!ai)
+               return -1;
+
+       comp_type = amd_appinfo_get_value(ai, AMD_AIT_COMPTYPE);
+       if (!comp_type)
+               return -1;
+
+       if (strcmp(comp_type, APP_TYPE_WIDGET) != 0)
+               return amd_cynara_simple_checker(info, req, PRIVILEGE_WIDGET_VIEWER);
+
+       return amd_cynara_simple_checker(info, req, data);
+}
+
+static amd_request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = WIDGET_ADD,
+               .callback = __dispatch_widget_add_del
+       },
+       {
+               .cmd = WIDGET_DEL,
+               .callback = __dispatch_widget_add_del
+       },
+       {
+               .cmd = WIDGET_LIST,
+               .callback = __dispatch_widget_list
+       },
+       {
+               .cmd = WIDGET_UPDATE,
+               .callback = __dispatch_widget_update
+       },
+       {
+               .cmd = WIDGET_COUNT,
+               .callback = __dispatch_widget_count
+       },
+       {
+               .cmd = WIDGET_GET_CONTENT,
+               .callback = __dispatch_widget_get_content
+       },
+       {
+               .cmd = WIDGET_NOTIFY_EXIT,
+               .callback = __dispatch_widget_notify_exit
+       },
+
+};
+
+static amd_cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = APP_TERM_BY_PID_ASYNC,
+               .checker = __app_term_by_pid_async_checker,
+               .data = PRIVILEGE_APPMANAGER_KILL,
+               .priority = 10,
+       },
+};
+
+static int __on_app_dead(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       amd_app_status_h app_status = arg3;
+       int pid = arg1;
+       uid_t uid = arg2;
+       bool is_widget;
+       const char *pkgid;
+
+       is_widget = __widget_exist(pid, uid);
+       if (is_widget) {
+               pkgid = amd_app_status_get_pkgid(app_status);
+               __widget_send_dead_signal(pid, uid, pkgid);
+       }
+
+       return 0;
+}
+
+static int __on_app_status_destroy(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_app_status_h app_status = arg3;
+
+       if (amd_app_status_get_app_type(app_status) == AMD_AT_WIDGET_APP) {
+               __widget_cleanup(amd_app_status_get_pid(app_status),
+                               amd_app_status_get_uid(app_status));
+       }
+
+       return 0;
+}
+
+static int __on_launching_widget(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       amd_request_h req = arg3;
+
+       if (__widget_verify_cmd(req) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int __widget_viewer_checker(amd_cynara_caller_info_h info, amd_request_h req)
+{
+       char *appid = NULL;
+       const char *apptype;
+       amd_appinfo_h appinfo;
+       bundle *appcontrol = amd_request_get_bundle(req);
+
+       if (!appcontrol) {
+               LOGE("wrong argument");
+               return AMD_CYNARA_RET_ERROR;
+       }
+
+       bundle_get_str(appcontrol, AUL_K_APPID, &appid);
+       if (!appid) {
+               LOGE("can not resolve appid. request denied.");
+               return AMD_CYNARA_RET_ERROR;
+       }
+
+       appinfo = amd_appinfo_find(amd_request_get_target_uid(req), appid);
+       if (!appinfo) {
+               LOGE("can not resolve appinfo of %s. request denied.", appid);
+               return AMD_CYNARA_RET_ERROR;
+
+       }
+
+       apptype = amd_appinfo_get_value(appinfo, AMD_AIT_COMPTYPE);
+       if (!apptype) {
+               LOGE("can not resolve apptype of %s. request denied.", appid);
+               return AMD_CYNARA_RET_ERROR;
+       }
+
+       if (!strcmp(apptype, APP_TYPE_WIDGET) ||
+                       !strcmp(apptype, APP_TYPE_WATCH))
+               return amd_cynara_simple_checker(info, req, PRIVILEGE_WIDGET_VIEWER);
+
+       LOGE("illegal app type of request: %s - " \
+                       "only widget or watch apps are allowed", apptype);
+
+       return AMD_CYNARA_RET_ERROR;
+}
+
+static int __appcontrol_sub_checker(amd_cynara_caller_info_h info, amd_request_h req)
+{
+       bundle *appcontrol;
+       char *op = NULL;
+       int ret;
+
+       appcontrol = amd_request_get_bundle(req);
+       if (!appcontrol)
+               return AMD_CYNARA_RET_CONTINUE;
+
+       ret = bundle_get_str(appcontrol, AUL_SVC_K_OPERATION, &op);
+       if (ret != BUNDLE_ERROR_NONE)
+               return AMD_CYNARA_RET_CONTINUE;
+
+       if (!op || strcmp(op, AUL_SVC_OPERATION_LAUNCH_WIDGET))
+               return AMD_CYNARA_RET_CONTINUE;
+
+       return __widget_viewer_checker(info, req);
+}
+
+EXPORT int AMD_MOD_INIT(void)
+{
+       int r;
+
+       LOGD("widget init");
+       r = amd_request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               LOGE("Failed to register cmds");
+               return -1;
+       }
+
+       r = amd_cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (r < 0) {
+               LOGE("Failed to register checkers");
+               return -1;
+       }
+
+       amd_noti_listen("main.app_dead", __on_app_dead);
+       amd_noti_listen("app_status.destroy", __on_app_status_destroy);
+       amd_noti_listen("launch.prepare.widget", __on_launching_widget);
+
+       amd_cynara_sub_checker_add("appcontrol", __appcontrol_sub_checker);
+
+       return 0;
+}
+
+EXPORT void AMD_MOD_FINI(void)
+{
+       LOGD("widget fini");
+
+       if (__widgets)
+               g_list_free_full(__widgets, __free_widget);
+}
diff --git a/packaging/ac.conf b/packaging/ac.conf
new file mode 100644 (file)
index 0000000..f06cc3a
--- /dev/null
@@ -0,0 +1,15 @@
+d      /run/aul        1755    root    root
+t      /run/aul        -       -       -       -       security.SMACK64="System::Run"
+t      /run/aul        -       -       -       -       security.SMACK64TRANSMUTE="TRUE"
+d      /run/aul/apps   1777    root    root
+t      /run/aul/apps   -       -       -       -       security.SMACK64="*"
+t      /run/aul/apps   -       -       -       -       security.SMACK64TRANSMUTE="TRUE"
+d      /run/aul/daemons        1777    root    root
+t      /run/aul/daemons        -       -       -       -       security.SMACK64="User::Home"
+t      /run/aul/daemons        -       -       -       -       security.SMACK64TRANSMUTE="TRUE"
+d      /run/aul/dbspace        1777    root    root
+t      /run/aul/dbspace        -       -       -       -       security.SMACK64="User::Home"
+t      /run/aul/dbspace        -       -       -       -       security.SMACK64TRANSMUTE="TRUE"
+d      /run/aul/log    1777    root    root
+t      /run/aul/log    -       -       -       -       security.SMACK64="User::Home"
+t      /run/aul/log    -       -       -       -       security.SMACK64TRANSMUTE="TRUE"
diff --git a/packaging/ac.service b/packaging/ac.service
new file mode 100644 (file)
index 0000000..9cc1c8b
--- /dev/null
@@ -0,0 +1,26 @@
+#
+#  Systemd script to Launch AMD
+#
+
+[Unit]
+Description=Start Application Management Daemon
+DefaultDependencies=false
+Requires=dbus.socket tizen-system-env.service
+After=dbus.socket tizen-system-env.service
+
+[Service]
+User=app_fw
+Group=app_fw
+SmackProcessLabel=System
+Capabilities=cap_setuid,cap_setgid,cap_mac_admin,cap_kill,cap_dac_override=i
+SecureBits=keep-caps
+Type=notify
+EnvironmentFile=/run/tizen-system-env
+EnvironmentFile=/run/xdg-root-env
+ExecStart=/usr/bin/amd
+OOMScoreAdjust=-100
+Restart=on-failure
+RestartSec=3
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packaging/ac.socket b/packaging/ac.socket
new file mode 100644 (file)
index 0000000..74bf73d
--- /dev/null
@@ -0,0 +1,7 @@
+[Socket]
+ListenStream=/run/aul/daemons/.amd-sock
+SocketMode=0777
+DirectoryMode=0777
+
+[Install]
+WantedBy=sockets.target
diff --git a/packaging/amd.manifest b/packaging/amd.manifest
new file mode 100644 (file)
index 0000000..81ace0c
--- /dev/null
@@ -0,0 +1,6 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
+
diff --git a/packaging/amd.spec b/packaging/amd.spec
new file mode 100644 (file)
index 0000000..461130a
--- /dev/null
@@ -0,0 +1,274 @@
+Name:       amd
+Summary:    Application Management Daemon
+Version:    1.1.3
+Release:    1
+Group:      Application Framework/Service
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+Source100:  ac.conf
+Source101:  ac.service
+Source102:  ac.socket
+Source1001: %{name}.manifest
+
+Requires(post):   /sbin/ldconfig
+Requires(post):   /usr/bin/systemctl
+Requires(postun): /sbin/ldconfig
+Requires(postun): /usr/bin/systemctl
+Requires(preun):  /usr/bin/systemctl
+Requires:   tizen-platform-config
+
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(gio-2.0)
+BuildRequires:  pkgconfig(bundle)
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(security-manager)
+BuildRequires:  pkgconfig(rua)
+BuildRequires:  pkgconfig(aul)
+BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(pkgmgr-info)
+BuildRequires:  pkgconfig(pkgmgr)
+BuildRequires:  pkgconfig(libtzplatform-config)
+BuildRequires:  pkgconfig(libsystemd)
+BuildRequires:  pkgconfig(cynara-client-async)
+BuildRequires:  pkgconfig(cynara-creds-socket)
+BuildRequires:  pkgconfig(cynara-session)
+BuildRequires:  pkgconfig(cert-svc-vcore)
+BuildRequires:  pkgconfig(xkbcommon)
+BuildRequires:  pkgconfig(sensor)
+BuildRequires:  pkgconfig(ttrace)
+BuildRequires:  pkgconfig(app2sd)
+BuildRequires:  pkgconfig(capi-network-connection)
+BuildRequires:  pkgconfig(wayland-client)
+BuildRequires:  pkgconfig(tizen-extension-client)
+BuildRequires:  pkgconfig(tizen-launch-client)
+BuildRequires:  pkgconfig(wayland-tbm-client)
+BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  pkgconfig(libsmack)
+
+%description
+Application management daemon
+
+%package devel
+Summary:    Application Management Daemon (devel)
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+Application Management Daemon (devel)
+
+%package -n amd-mod-launchpad
+Summary:    AMD Module Launchpad
+Group:      Application Framework/Service
+Requires(post):  /usr/sbin/setcap
+Requires(post):  /usr/bin/chsmack
+Requires(postun):  /usr/sbin/setcap
+Requires(postun):  /usr/bin/chsmack
+
+%description -n amd-mod-launchpad
+AMD Module Launchpad
+
+%package -n amd-mod-cooldown
+Summary:    AMD module for supporting feature 'cool-down'
+Group:      Application Framework/Service
+
+%description -n amd-mod-cooldown
+This module is for supporting feature 'cool-down'
+
+%package -n amd-mod-wayland-core
+Summary:    AMD module for connecting display server
+Group:      Application Framework/Service
+
+%description -n amd-mod-wayland-core
+This module is for connecting display server
+
+%package -n amd-mod-splash-screen
+Summary:    AMD module for supporting feature 'splash-screen'
+Group:      Application Framework/Service
+
+%description -n amd-mod-splash-screen
+This module is for supporting feature 'splash-screen'
+
+%package -n amd-mod-input
+Summary:    AMD module for controlling key and mouse events
+Group:      Application Framework/Service
+
+%description -n amd-mod-input
+This module is for controlling key and mouse events
+
+%package -n amd-mod-widget
+Summary:    AMD module for widgets
+Group:      Application Framework/Service
+
+%description -n amd-mod-widget
+This module is for supporting widgets
+
+%package -n amd-mod-share
+Summary:    AMD module for sharing application's private files
+Group:      Application Framework/Service
+
+%description -n amd-mod-share
+This module is for supporting sharing of application's private files
+
+%package -n amd-mod-ui-core
+Summary:    AMD module for supporting UI related features
+Group:      Application Framework/Service
+
+%description -n amd-mod-ui-core
+This module is for supporting UI related features such as 'app-group' and 'rua'
+
+%package -n amd-mod-extractor
+Summary:    AMD module for mounting and unmouting tizen package files
+Group:      Application Framework/Service
+
+%description -n amd-mod-extractor
+This module is for mounting and unmouting tizen package files such as '.tep' and '.tpk'
+
+%package -n amd-mod-cynara-core
+Summary:    AMD module for access-control
+Group:      Application Framework/Service
+
+%description -n amd-mod-cynara-core
+This module is for checking privileges
+
+%package -n amd-mod-rua
+Summary:    AMD module for managing recently-used-application
+Group:      Application Framework/Service
+
+%description -n amd-mod-rua
+This module is for managing recently-used-application
+
+%define _moddir %{_datadir}/amd
+
+%prep
+%setup -q
+sed -i 's|TZ_SYS_DB|%{TZ_SYS_DB}|g' %{SOURCE1001}
+cp %{SOURCE1001} .
+
+%build
+%if 0%{?simulator}
+CFLAGS="%{optflags} -D__emul__"; export CFLAGS
+%endif
+
+%if 0%{?tizen_feature_terminate_unmanageable_app}
+_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP=ON
+%endif
+%if 0%{?tizen_feature_block_input}
+_TIZEN_FEATURE_BLOCK_INPUT=ON
+%endif
+
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+%cmake -DFULLVER=%{version} \
+       -DMAJORVER=${MAJORVER} \
+       -DAMD_MODULES_DIR=%{_moddir} \
+       .
+
+%__make %{?_smp_mflags}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+mkdir -p %{buildroot}%{_tmpfilesdir}
+mkdir -p %{buildroot}%{_unitdir}/multi-user.target.wants
+mkdir -p %{buildroot}%{_unitdir}/sockets.target.wants
+install -m 0644 %SOURCE100 %{buildroot}%{_tmpfilesdir}/ac.conf
+install -m 0644 %SOURCE101 %{buildroot}%{_unitdir}/ac.service
+install -m 0644 %SOURCE102 %{buildroot}%{_unitdir}/ac.socket
+ln -sf ../ac.service %{buildroot}%{_unitdir}/multi-user.target.wants/ac.service
+ln -sf ../ac.socket %{buildroot}%{_unitdir}/sockets.target.wants/ac.socket
+
+%preun
+if [ $1 == 0 ]; then
+    systemctl stop ac.service
+    systemctl disable ac
+fi
+
+%post
+/sbin/ldconfig
+
+systemctl daemon-reload
+if [ $1 == 1 ]; then
+    systemctl restart ac.service
+fi
+
+%postun
+/sbin/ldconfig
+systemctl daemon-reload
+
+%post -n amd-mod-launchpad
+/sbin/ldconfig
+/usr/bin/chsmack -e "System::Privileged" %{_bindir}/amd
+
+%files
+%license LICENSE
+%manifest %{name}.manifest
+%{_tmpfilesdir}/ac.conf
+%{_unitdir}/ac.service
+%{_unitdir}/multi-user.target.wants/ac.service
+%{_unitdir}/ac.socket
+%{_unitdir}/sockets.target.wants/ac.socket
+%{_bindir}/amd
+%{_libdir}/libamd.so.*
+%{_moddir}/libamd.so
+
+%files devel
+%{_includedir}/amd/*.h
+%{_libdir}/libamd.so
+%{_libdir}/pkgconfig/*pc
+
+%files -n amd-mod-launchpad
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-launchpad.so
+
+%files -n amd-mod-cooldown
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-cooldown.so
+
+%files -n amd-mod-wayland-core
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-wayland-core.so
+
+%files -n amd-mod-splash-screen
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-splash-screen.so
+
+%files -n amd-mod-input
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-input.so
+
+%files -n amd-mod-widget
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-widget.so
+
+%files -n amd-mod-share
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-share.so
+
+%files -n amd-mod-ui-core
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-ui-core.so
+
+%files -n amd-mod-extractor
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-extractor.so
+
+%files -n amd-mod-cynara-core
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-cynara-core.so
+
+%files -n amd-mod-rua
+%manifest %{name}.manifest
+%license LICENSE
+%{_moddir}/mod/libamd-mod-rua.so
+
diff --git a/src/amd/main.c b/src/amd/main.c
new file mode 100644 (file)
index 0000000..0869ab0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <dlfcn.h>
+
+#define PATH_LIB_AMD "/usr/share/amd/libamd.so"
+
+int main(int argc, char *argv[])
+{
+       void *handle;
+       int (*dl_main)(int, char **);
+
+       handle = dlopen(PATH_LIB_AMD, RTLD_LAZY | RTLD_GLOBAL);
+       if (!handle) {
+               fprintf(stderr, "Failed to load - %s", dlerror());
+               return -1;
+       }
+
+       dl_main = dlsym(handle, "main");
+       if (!dl_main) {
+               fprintf(stderr, "Failed to find main function");
+               dlclose(handle);
+               return -1;
+       }
+
+       return dl_main(argc, argv);
+}
diff --git a/src/lib/amd_api_app_com.c b/src/lib/amd_api_app_com.c
new file mode 100644 (file)
index 0000000..a777a0d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "amd_api.h"
+#include "amd_api_app_com.h"
+#include "amd_app_com.h"
+
+EXPORT_API int amd_app_com_send(const char *endpoint, int cpid,
+               bundle *envelope, uid_t uid)
+{
+       return _app_com_send(endpoint, cpid, envelope, uid);
+}
+
diff --git a/src/lib/amd_api_app_status.c b/src/lib/amd_api_app_status.c
new file mode 100644 (file)
index 0000000..690d9fc
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include "amd_app_status.h"
+#include "amd_api.h"
+#include "amd_api_app_status.h"
+
+EXPORT_API amd_app_status_h amd_app_status_find_by_effective_pid(int pid)
+{
+       return _app_status_find_v2(pid);
+}
+
+EXPORT_API amd_app_status_h amd_app_status_find_by_pid(int pid)
+{
+       return _app_status_find(pid);
+}
+
+EXPORT_API amd_app_status_h amd_app_status_find_by_appid(const char *appid,
+               uid_t uid)
+{
+       return _app_status_find_by_appid(appid, uid);
+}
+
+EXPORT_API int amd_app_status_get_pid(amd_app_status_h h)
+{
+       return _app_status_get_pid(h);
+}
+
+EXPORT_API uid_t amd_app_status_get_uid(amd_app_status_h h)
+{
+       return _app_status_get_uid(h);
+}
+
+EXPORT_API int amd_app_status_get_status(amd_app_status_h h)
+{
+       return _app_status_get_status(h);
+}
+
+EXPORT_API bool amd_app_status_is_home_app(amd_app_status_h h)
+{
+       return _app_status_is_home_app(h);
+}
+
+EXPORT_API int amd_app_status_get_first_caller_pid(amd_app_status_h h)
+{
+       return _app_status_get_org_caller_pid(h);
+}
+
+EXPORT_API const char *amd_app_status_get_appid(amd_app_status_h h)
+{
+       return _app_status_get_appid(h);
+}
+
+EXPORT_API const char *amd_app_status_get_pkgid(amd_app_status_h h)
+{
+       return _app_status_get_pkgid(h);
+}
+
+EXPORT_API const char *amd_app_status_get_instance_id(amd_app_status_h h)
+{
+       return _app_status_get_instance_id(h);
+}
+
+EXPORT_API int amd_app_status_foreach_running_info(amd_app_status_cb callback,
+               void *user_data)
+{
+       return _app_status_foreach_running_appinfo(callback, user_data);
+}
+
+EXPORT_API int amd_app_status_terminate_apps(const char *appid, uid_t uid)
+{
+       return _app_status_terminate_apps(appid, uid);
+}
+
+EXPORT_API bool amd_app_status_is_starting(amd_app_status_h h)
+{
+       return _app_status_is_starting(h);
+}
+
+EXPORT_API int amd_app_status_get_app_type(amd_app_status_h app_status)
+{
+       return _app_status_get_app_type(app_status);
+}
+
+EXPORT_API int amd_app_status_set_extra(amd_app_status_h app_status,
+               const char *key, void *data)
+{
+       return _app_status_set_extra(app_status, key, data);
+}
+
+EXPORT_API int amd_app_status_remove_extra(amd_app_status_h app_status,
+               const char *key)
+{
+       return _app_status_remove_extra(app_status, key);
+}
+
+EXPORT_API void *amd_app_status_get_extra(amd_app_status_h app_status,
+               const char *key)
+{
+       return _app_status_get_extra(app_status, key);
+}
+
+EXPORT_API int amd_app_status_get_leader_pid(amd_app_status_h app_status)
+{
+       return _app_status_get_leader_pid(app_status);
+}
+
+EXPORT_API int amd_app_status_set_leader_pid(amd_app_status_h app_status, int pid)
+{
+       return _app_status_set_leader_pid(app_status, pid);
+}
+
+EXPORT_API int amd_app_status_get_fg_cnt(amd_app_status_h app_status)
+{
+       return _app_status_get_fg_cnt(app_status);
+}
+
+EXPORT_API int amd_app_status_get_timestamp(amd_app_status_h app_status)
+{
+       return _app_status_get_timestamp(app_status);
+}
+
+EXPORT_API int amd_app_status_term_bg_apps(GCompareFunc func)
+{
+       return _app_status_term_bg_apps(func);
+}
+
+EXPORT_API bool amd_app_status_get_bg_launch(amd_app_status_h app_status)
+{
+       return _app_status_get_bg_launch(app_status);
+}
+
+EXPORT_API amd_app_status_h amd_app_status_find_by_instance_id(const char *appid,
+               const char *instance_id, uid_t uid)
+{
+       return _app_status_find_by_instance_id(appid, instance_id, uid);
+}
+
+EXPORT_API void amd_app_status_find_service_apps(amd_app_status_h app_status,
+               int status, void (*send_event_to_svc_core)(int, uid_t),
+               bool suspend)
+{
+       _app_status_find_service_apps(app_status, status,
+                       send_event_to_svc_core, suspend);
+}
+
+EXPORT_API int amd_app_status_get_process_cnt(const char *appid)
+{
+       return _app_status_get_process_cnt(appid);
+}
+
+EXPORT_API const char *amd_app_status_get_app_path(amd_app_status_h app_status)
+{
+       return _app_status_get_app_path(app_status);
+}
+
diff --git a/src/lib/amd_api_appinfo.c b/src/lib/amd_api_appinfo.c
new file mode 100644 (file)
index 0000000..e085d73
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include "amd_api.h"
+#include "amd_appinfo.h"
+#include "amd_api_appinfo.h"
+
+EXPORT_API int amd_appinfo_insert(uid_t uid, const char *pkgid)
+{
+       return _appinfo_insert(uid, pkgid);
+}
+
+EXPORT_API amd_appinfo_h amd_appinfo_find(uid_t caller_uid, const char *appid)
+{
+       return _appinfo_find(caller_uid, appid);
+}
+
+EXPORT_API const char *amd_appinfo_get_value(amd_appinfo_h h,
+               amd_appinfo_type type)
+{
+       return _appinfo_get_value(h, (enum appinfo_type)type);
+}
+
+EXPORT_API const void *amd_appinfo_get_ptr_value(amd_appinfo_h h,
+               amd_appinfo_type type)
+{
+       return _appinfo_get_ptr_value(h, (enum appinfo_type)type);
+}
+
+EXPORT_API int amd_appinfo_get_int_value(amd_appinfo_h h, amd_appinfo_type type,
+               int *val)
+{
+       return _appinfo_get_int_value(h, (enum appinfo_type)type, val);
+}
+
+EXPORT_API int amd_appinfo_get_boolean(amd_appinfo_h h, amd_appinfo_type type,
+               bool *val)
+{
+       return _appinfo_get_boolean(h, (enum appinfo_type)type, val);
+}
+
+EXPORT_API int amd_appinfo_set_value(amd_appinfo_h h, amd_appinfo_type type,
+               const char *val)
+{
+       return _appinfo_set_value(h, (enum appinfo_type)type, val);
+}
+
+EXPORT_API int amd_appinfo_set_ptr_value(amd_appinfo_h h, amd_appinfo_type type,
+               void *val)
+{
+       return _appinfo_set_ptr_value(h, (enum appinfo_type)type, val);
+}
+
+EXPORT_API int amd_appinfo_set_int_value(amd_appinfo_h h, amd_appinfo_type type,
+               int val)
+{
+       return _appinfo_set_int_value(h, (enum appinfo_type)type, val);
+}
+
+EXPORT_API void amd_appinfo_foreach(uid_t uid, amd_appinfo_iter_callback cb,
+               void *user_data)
+{
+       return _appinfo_foreach(uid, cb, user_data);
+}
+
+EXPORT_API int amd_appinfo_load(uid_t uid)
+{
+       return _appinfo_load(uid);
+}
+
+EXPORT_API void amd_appinfo_unload(uid_t uid)
+{
+       return _appinfo_unload(uid);
+}
+
+EXPORT_API amd_appinfo_splash_image_h amd_appinfo_find_splash_image(
+               amd_appinfo_h h, const char *name, bool landscape)
+{
+       return _appinfo_find_splash_image(h, name, landscape);
+}
+
+EXPORT_API const char *amd_appinfo_splash_image_get_source(
+               amd_appinfo_splash_image_h h)
+{
+       return _appinfo_splash_image_get_source(h);
+}
+
+EXPORT_API const char *amd_appinfo_splash_image_get_type(
+               amd_appinfo_splash_image_h h)
+{
+       return _appinfo_splash_image_get_type(h);
+}
+
+EXPORT_API int amd_appinfo_splash_image_get_indicator_display(
+               amd_appinfo_splash_image_h h)
+{
+       return _appinfo_splash_image_get_indicator_display(h);
+}
+
+EXPORT_API int amd_appinfo_splash_image_get_color_depth(
+               amd_appinfo_splash_image_h h)
+{
+       return _appinfo_splash_image_get_color_depth(h);
+}
diff --git a/src/lib/amd_api_cynara.c b/src/lib/amd_api_cynara.c
new file mode 100644 (file)
index 0000000..fb55cad
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "amd_api.h"
+#include "amd_api_cynara.h"
+#include "amd_cynara.h"
+
+static cynara_ops __ops;
+static cynara_caller_info_ops __ci_ops;
+static amd_cynara_ops __amd_ops;
+static amd_cynara_caller_info_ops __amd_ci_ops;
+
+EXPORT_API int amd_cynara_check_privilege(amd_request_h req,
+               amd_cynara_response_cb callback)
+{
+       return _cynara_check_privilege(req, (cynara_response_cb)callback);
+}
+
+EXPORT_API int amd_cynara_register_checkers(const amd_cynara_checker *checkers,
+               int cnt)
+{
+       return _cynara_register_checkers((cynara_checker *)checkers, cnt);
+}
+
+EXPORT_API int amd_cynara_simple_checker(amd_cynara_caller_info_h info,
+               amd_request_h req, void *data)
+{
+       return _cynara_simple_checker(info, req, data);
+}
+
+EXPORT_API const char *amd_cynara_caller_info_get_client(
+               amd_cynara_caller_info_h info)
+{
+       return _cynara_caller_info_get_client(info);
+}
+
+EXPORT_API int amd_cynara_sub_checker_add(const char *name,
+               amd_cynara_sub_checker_func func)
+{
+       return _cynara_sub_checker_add(name, func);
+}
+
+EXPORT_API int amd_cynara_sub_checker_check(const char *name,
+               amd_cynara_caller_info_h info, amd_request_h req)
+{
+       return _cynara_sub_checker_check(name, info, req);
+}
+
+static int __register_checkers(const cynara_checker *checkers, int cnt)
+{
+       return __amd_ops.register_checkers((amd_cynara_checker *)checkers, cnt);
+}
+
+static int __sub_checker_add(const char *name, sub_checker_func func)
+{
+       return __amd_ops.sub_checker_add(name, func);
+}
+
+static int __sub_checker_check(const char *name, caller_info_h info, request_h req)
+{
+       return __amd_ops.sub_checker_check(name, info, req);
+}
+
+static int __check_async(request_h req, cynara_response_cb callback)
+{
+       return __amd_ops.check_async(req, (amd_cynara_response_cb)callback);
+}
+
+static int __check(caller_info_h info, request_h req, void *data)
+{
+       return __amd_ops.check(info, req, data);
+}
+
+static const char *__get_client(caller_info_h info)
+{
+       return __amd_ci_ops.get_client(info);
+}
+
+EXPORT_API int amd_cynara_register_ops(amd_cynara_ops ops,
+               amd_cynara_caller_info_ops ci_ops)
+{
+       __amd_ops = ops;
+       __amd_ci_ops = ci_ops;
+
+       __ops.register_checkers = __register_checkers;
+       __ops.sub_checker_add = __sub_checker_add;
+       __ops.sub_checker_check = __sub_checker_check;
+       __ops.check_async  = __check_async;
+       __ops.check = __check;
+       __ci_ops.get_client = __get_client;
+
+       return _cynara_register_ops(__ops, __ci_ops);
+}
+
diff --git a/src/lib/amd_api_inotify.c b/src/lib/amd_api_inotify.c
new file mode 100644 (file)
index 0000000..4a9489e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "amd_api.h"
+#include "amd_api_inotify.h"
+#include "amd_inotify.h"
+
+EXPORT_API int amd_inotify_add_watch(const char *path, uint32_t mask,
+               amd_inotify_watch_cb callback, void *data)
+{
+       return _inotify_add_watch(path, mask, callback, data);
+}
+
+EXPORT_API void amd_inotify_rm_watch(int wd)
+{
+       _inotify_rm_watch(wd);
+}
diff --git a/src/lib/amd_api_launch.c b/src/lib/amd_api_launch.c
new file mode 100644 (file)
index 0000000..c4d8016
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "amd_api.h"
+#include "amd_api_launch.h"
+#include "amd_launch.h"
+
+EXPORT_API int amd_launch_start_app(const char *appid, amd_request_h req, bool *pending,
+               bool *bg_launch, bool new_instance)
+{
+       return _launch_start_app(appid, req, pending, bg_launch, new_instance);
+}
+
+EXPORT_API int amd_launch_term_sub_app(int pid, uid_t uid)
+{
+       return _term_sub_app(pid, uid);
+}
+
+EXPORT_API int amd_launch_start_onboot_apps(uid_t uid)
+{
+       return _launch_start_onboot_apps(uid);
+}
diff --git a/src/lib/amd_api_launch_context.c b/src/lib/amd_api_launch_context.c
new file mode 100644 (file)
index 0000000..c847484
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include "amd_launch.h"
+#include "amd_api.h"
+#include "amd_api_launch_context.h"
+
+EXPORT_API amd_appinfo_h amd_launch_context_get_appinfo(
+               amd_launch_context_h h)
+{
+       return (amd_appinfo_h)_launch_context_get_appinfo(h);
+}
+
+EXPORT_API const char *amd_launch_context_get_appid(amd_launch_context_h h)
+{
+       return _launch_context_get_appid(h);
+}
+
+EXPORT_API const char *amd_launch_context_get_instance_id(
+               amd_launch_context_h h)
+{
+       return _launch_context_get_instance_id(h);
+}
+
+EXPORT_API int amd_launch_context_get_pid(amd_launch_context_h h)
+{
+       return _launch_context_get_pid(h);
+}
+
+EXPORT_API bool amd_launch_context_is_subapp(amd_launch_context_h h)
+{
+       return _launch_context_is_subapp(h);
+}
+
+EXPORT_API bool amd_launch_context_is_bg_launch(amd_launch_context_h h)
+{
+       return _launch_context_is_bg_launch(h);
+}
+
+EXPORT_API int amd_launch_context_set_pid(amd_launch_context_h h,
+               int pid)
+{
+       return _launch_context_set_pid(h, pid);
+}
+
+EXPORT_API bool amd_launch_context_is_new_instance(amd_launch_context_h h)
+{
+       return _launch_context_is_new_instance(h);
+}
+
+EXPORT_API int amd_launch_context_set_subapp(amd_launch_context_h h,
+               bool is_subapp)
+{
+       return _launch_context_set_subapp(h, is_subapp);
+}
+
+EXPORT_API int amd_launch_context_set_app_status(amd_launch_context_h h,
+               amd_app_status_h status)
+{
+       return _launch_context_set_app_status(h, status);
+}
+
diff --git a/src/lib/amd_api_launchpad.c b/src/lib/amd_api_launchpad.c
new file mode 100644 (file)
index 0000000..9d3ee3b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include "amd_launchpad.h"
+#include "amd_api.h"
+#include "amd_api_launchpad.h"
+
+EXPORT_API int amd_launchpad_set_launcher(amd_launcher_cb launcher,
+               void *user_data)
+{
+       return _launchpad_set_launcher(launcher, user_data);
+}
diff --git a/src/lib/amd_api_login_monitor.c b/src/lib/amd_api_login_monitor.c
new file mode 100644 (file)
index 0000000..89c3ea7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "amd_api.h"
+#include "amd_api_login_monitor.h"
+#include "amd_login_monitor.h"
+
+EXPORT_API int amd_login_monitor_get_uids(uid_t **uids)
+{
+       return _login_monitor_get_uids(uids);
+}
+
+EXPORT_API amd_uid_state amd_login_monitor_get_uid_state(uid_t uid)
+{
+       return _login_monitor_get_uid_state(uid);
+}
diff --git a/src/lib/amd_api_noti.c b/src/lib/amd_api_noti.c
new file mode 100644 (file)
index 0000000..7b04466
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "amd_noti.h"
+#include "amd_api.h"
+#include "amd_api_noti.h"
+
+EXPORT_API int amd_noti_send(const char *msg, int arg1, int arg2, void *arg3,
+               bundle *data)
+{
+       return _noti_send(msg, arg1, arg2, arg3, data);
+}
+
+EXPORT_API int amd_noti_listen(const char *msg, amd_noti_cb callback)
+{
+       return _noti_listen(msg, (noti_cb)callback);
+}
diff --git a/src/lib/amd_api_request.c b/src/lib/amd_api_request.c
new file mode 100644 (file)
index 0000000..e5b5b86
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "amd_api.h"
+#include "amd_api_request.h"
+#include "amd_request.h"
+
+EXPORT_API int amd_request_send_result(amd_request_h req, int res)
+{
+       return _request_send_result(req, res);
+}
+
+EXPORT_API int amd_request_send_raw(amd_request_h req, int cmd, unsigned char *data, int len)
+{
+       return _request_send_raw(req, cmd, data, len);
+}
+
+EXPORT_API int amd_request_get_fd(amd_request_h req)
+{
+       return _request_get_fd(req);
+}
+
+EXPORT_API int amd_request_get_pid(amd_request_h req)
+{
+       return _request_get_pid(req);
+}
+
+EXPORT_API int amd_request_get_cmd(amd_request_h req)
+{
+       return _request_get_cmd(req);
+}
+
+EXPORT_API int amd_request_set_cmd(amd_request_h req, int cmd)
+{
+       return _request_set_cmd(req, cmd);
+}
+
+EXPORT_API bundle *amd_request_get_bundle(amd_request_h req)
+{
+       return _request_get_bundle(req);
+}
+
+EXPORT_API amd_request_h amd_request_create_local(int cmd, uid_t uid, int pid, bundle *kb)
+{
+       return _request_create_local(cmd, uid, pid, kb);
+}
+
+EXPORT_API void amd_request_free_local(amd_request_h req)
+{
+       return _request_free_local(req);
+}
+
+EXPORT_API int amd_request_remove_fd(amd_request_h req)
+{
+       return _request_remove_fd(req);
+}
+
+EXPORT_API int amd_request_reply_for_pending_request(int pid)
+{
+       return _request_reply_for_pending_request(pid);
+}
+
+EXPORT_API int amd_request_flush_pending_request(int pid)
+{
+       return _request_flush_pending_request(pid);
+}
+
+EXPORT_API uid_t amd_request_get_target_uid(amd_request_h req)
+{
+       return _request_get_target_uid(req);
+}
+
+EXPORT_API uid_t amd_request_get_uid(amd_request_h req)
+{
+       return _request_get_uid(req);
+}
+
+EXPORT_API pid_t amd_request_get_target_pid(amd_request_h req)
+{
+       return _request_get_target_pid(req);
+}
+
+EXPORT_API int amd_request_usr_init(uid_t uid)
+{
+       return _request_usr_init(uid);
+}
+
+EXPORT_API int amd_request_register_cmds(const amd_request_cmd_dispatch *cmds, int cnt)
+{
+       return _request_register_cmds((request_cmd_dispatch *)cmds, cnt);
+}
+
+EXPORT_API int amd_request_reply_append(int pid, void *reply)
+{
+       return _request_reply_append(pid, reply);
+}
+
+EXPORT_API int amd_request_reply_remove(int pid, void *reply)
+{
+       return _request_reply_remove(pid, reply);
+}
+
+EXPORT_API amd_request_reply_h amd_request_reply_create_full(amd_request_h req,
+               pid_t pid, int result, int cmd, void *extra,
+               void (*extra_free_cb)(void *data))
+{
+       return _request_reply_create_full(req, pid, result, cmd, extra, extra_free_cb);
+}
+
+EXPORT_API int amd_request_reply_foreach_extra(int pid, int (*callback)(void *data))
+{
+       return _request_reply_foreach_extra(pid, callback);
+}
+
+EXPORT_API int amd_request_get_len(amd_request_h req)
+{
+       return _request_get_len(req);
+}
+
+EXPORT_API unsigned char *amd_request_get_raw(amd_request_h req)
+{
+       return _request_get_raw(req);
+}
+
+EXPORT_API GTimeVal *amd_request_get_start_time(amd_request_h req)
+{
+       return _request_get_start_time(req);
+}
+
diff --git a/src/lib/amd_api_signal.c b/src/lib/amd_api_signal.c
new file mode 100644 (file)
index 0000000..5b1830d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include "amd_api.h"
+#include "amd_api_signal.h"
+#include "amd_signal.h"
+
+EXPORT_API int amd_signal_send_tep_mount(char *mnt_path[], const char *pkgid)
+{
+       return _signal_send_tep_mount(mnt_path, pkgid);
+}
+
+EXPORT_API int amd_signal_send_tep_unmount(const char *mnt_path)
+{
+       return _signal_send_tep_unmount(mnt_path);
+}
diff --git a/src/lib/amd_api_suspend.c b/src/lib/amd_api_suspend.c
new file mode 100644 (file)
index 0000000..7c5e663
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "amd_api.h"
+#include "amd_suspend.h"
+#include "amd_api_suspend.h"
+
+EXPORT_API int amd_suspend_add_proc(int pid)
+{
+       return _suspend_add_proc(pid);
+}
+
+EXPORT_API int amd_suspend_remove_proc(int pid)
+{
+       return _suspend_remove_proc(pid);
+}
+
+EXPORT_API bool amd_suspend_is_allowed_background(amd_appinfo_h ai)
+{
+       return _suspend_is_allowed_background(ai);
+}
+
+EXPORT_API void amd_suspend_add_timer(int pid)
+{
+        _suspend_add_timer(pid);
+}
+
+EXPORT_API void amd_suspend_remove_timer(int pid)
+{
+       _suspend_remove_timer(pid);
+}
+
+EXPORT_API int amd_suspend_update_status(int pid, int status)
+{
+       return _suspend_update_status(pid, status);
+}
+
diff --git a/src/lib/amd_api_wayland.c b/src/lib/amd_api_wayland.c
new file mode 100644 (file)
index 0000000..1d29c85
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include "amd_api.h"
+#include "amd_api_wayland.h"
+
+static void *__display;
+static void *__tizen_policy;
+
+EXPORT_API void *amd_wayland_get_display(void)
+{
+       return __display;
+}
+
+EXPORT_API void amd_wayland_set_display(void *display)
+{
+       __display = display;
+}
+
+EXPORT_API void *amd_wayland_get_tizen_policy(void)
+{
+       return __tizen_policy;
+}
+
+EXPORT_API void amd_wayland_set_tizen_policy(void *tizen_policy)
+{
+       __tizen_policy = tizen_policy;
+}
diff --git a/src/lib/amd_app_com.c b/src/lib/amd_app_com.c
new file mode 100644 (file)
index 0000000..22b4677
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <aul.h>
+#include <aul_cmd.h>
+#include <aul_app_com.h>
+#include <aul_sock.h>
+
+#include "amd_util.h"
+#include "amd_app_com.h"
+#include "amd_request.h"
+#include "amd_cynara.h"
+
+struct endpoint_info {
+       char *endpoint;
+       unsigned int propagate;
+       char *privilege;
+       GList *clients;
+};
+
+struct client_info {
+       int pid;
+       uid_t uid;
+       char *filter;
+       struct endpoint_info *endpoint;
+};
+
+static GHashTable *cpid_tbl;
+static GHashTable *endpoint_tbl;
+
+static void __remove_client(struct endpoint_info *info, int cpid);
+
+static void __free_endpoint(struct endpoint_info *info)
+{
+       if (!info)
+               return;
+
+       if (info->endpoint)
+               g_free(info->endpoint);
+
+       if (info->privilege)
+               g_free(info->privilege);
+
+       if (info->clients)
+               g_list_free(info->clients);
+
+       g_free(info);
+}
+
+static void __remove_cpid(gpointer key, gpointer value, gpointer user_data)
+{
+       int pid = GPOINTER_TO_INT(key);
+       struct endpoint_info *info;
+       GList *client_list = (GList *)value;
+
+       while (client_list) {
+               info = (struct endpoint_info *)client_list->data;
+               __remove_client(info, pid);
+               client_list = client_list->next;
+       }
+       g_list_free((GList *)value);
+}
+
+static int __app_com_add_endpoint(const char *endpoint, unsigned int propagate,
+               const char *assoc_priv)
+{
+       struct endpoint_info *info;
+
+       info = g_hash_table_lookup(endpoint_tbl, endpoint);
+       if (info) {
+               _E("endpoint already exists.");
+               return AUL_APP_COM_R_ERROR_ENDPOINT_ALREADY_EXISTS;
+       }
+
+       _D("endpoint=%s propagate=%d assoc_priv=%s",
+                       endpoint, propagate, assoc_priv);
+
+       info = (struct endpoint_info *)g_malloc0(sizeof(struct endpoint_info));
+       if (info == NULL) {
+               _E("out of memory");
+               return AUL_APP_COM_R_ERROR_OUT_OF_MEMORY;
+       }
+
+       info->endpoint = g_strdup(endpoint);
+       if (info->endpoint == NULL) {
+               _E("Out of memory");
+               g_free(info);
+               return AUL_APP_COM_R_ERROR_OUT_OF_MEMORY;
+       }
+       info->propagate = propagate;
+       info->clients = NULL;
+
+       if (assoc_priv) {
+               info->privilege = g_strdup(assoc_priv);
+               if (info->privilege == NULL) {
+                       _E("Out of memory");
+                       g_free(info->endpoint);
+                       g_free(info);
+                       return AUL_APP_COM_R_ERROR_OUT_OF_MEMORY;
+               }
+       } else {
+               info->privilege = NULL;
+       }
+
+       g_hash_table_insert(endpoint_tbl, info->endpoint, info);
+
+       return AUL_APP_COM_R_ERROR_OK;
+}
+
+static int __app_com_remove_endpoint(const char *endpoint)
+{
+       struct endpoint_info *info;
+
+       info = g_hash_table_lookup(endpoint_tbl, endpoint);
+       if (!info) {
+               _D("endpoint not exists");
+               return AUL_APP_COM_R_ERROR_UNKNOWN_ENDPOINT;
+       }
+
+       if (info->clients != NULL) {
+               _D("client active");
+               return AUL_APP_COM_R_ERROR_CLIENT_REMAINING;
+       }
+
+       g_hash_table_remove(endpoint_tbl, endpoint);
+       __free_endpoint(info);
+
+       return AUL_APP_COM_R_ERROR_OK;
+}
+
+static struct client_info *__add_client(struct endpoint_info *info,
+               const char *filter, int pid, uid_t uid)
+{
+       GList *client_list;
+       struct client_info *c;
+
+       c = (struct client_info *)g_malloc0(sizeof(struct client_info));
+       if (c == NULL) {
+               _E("out of memory");
+               return NULL;
+       }
+
+       c->endpoint = info;
+       c->pid = pid;
+       c->uid = uid;
+       if (filter) {
+               c->filter = g_strdup(filter);
+               if (c->filter == NULL) {
+                       _E("Out of memory");
+                       g_free(c);
+                       return NULL;
+               }
+       } else {
+               c->filter = NULL;
+       }
+
+       info->clients = g_list_append(info->clients, c);
+       client_list = g_hash_table_lookup(cpid_tbl, GINT_TO_POINTER(pid));
+       if (client_list == NULL) {
+               client_list = g_list_append(client_list, info);
+               g_hash_table_insert(cpid_tbl, GINT_TO_POINTER(pid),
+                               client_list);
+       } else {
+               client_list = g_list_append(client_list, info);
+       }
+
+       return c;
+}
+
+static int __app_com_join(const char *endpoint, int cpid, const char *filter,
+               uid_t uid)
+{
+       struct endpoint_info *info;
+
+       info = g_hash_table_lookup(endpoint_tbl, endpoint);
+       if (!info) {
+               _E("endpoint not exists: %s", endpoint);
+               return AUL_APP_COM_R_ERROR_UNKNOWN_ENDPOINT;
+       }
+
+       _D("endpoint=%s cpid=%d filter=%s uid=%d", endpoint, cpid, filter, uid);
+
+       if (__add_client(info, filter, cpid, uid) == NULL)
+               return AUL_APP_COM_R_ERROR_OUT_OF_MEMORY;
+
+       return AUL_APP_COM_R_ERROR_OK;
+}
+
+const char *_app_com_get_privilege(const char *endpoint)
+{
+       struct endpoint_info *info;
+
+       info = g_hash_table_lookup(endpoint_tbl, endpoint);
+       if (!info) {
+               _E("endpoint not exists: %s", endpoint);
+               return NULL;
+       }
+
+       return info->privilege;
+}
+
+static int __check_filter(const char *filter, int cpid, int rpid, bundle *b)
+{
+       /* TODO */
+       return 0;
+}
+
+int _app_com_send(const char *endpoint, int cpid, bundle *envelope, uid_t uid)
+{
+       struct endpoint_info *info;
+       GList *client_head;
+       struct client_info *client;
+       int ret;
+       int result = AUL_APP_COM_R_OK;
+
+       info = g_hash_table_lookup(endpoint_tbl, endpoint);
+       if (!info) {
+               _E("endpoint not exists: %s", endpoint);
+               return AUL_APP_COM_R_ERROR_UNKNOWN_ENDPOINT;
+       }
+
+       /* TODO delete internal keys */
+
+       _D("endpoint=%s cpid=%d", endpoint, cpid);
+
+       bundle_add_str(envelope, AUL_K_COM_ENDPOINT, endpoint);
+       bundle_add_byte(envelope, AUL_K_COM_RESULT, &result, sizeof(result));
+
+       client_head = info->clients;
+       while (client_head) {
+               client = (struct client_info *)client_head->data;
+               client_head = client_head->next;
+               if (client == NULL)
+                       continue;
+               if (client->pid == cpid)
+                       continue;
+               if (client->uid >= REGULAR_UID_MIN && client->uid != uid)
+                       continue;
+
+               if (client->filter) {
+                       ret = __check_filter(client->filter, cpid, client->pid,
+                                       envelope);
+                       if (ret < 0)
+                               continue;
+               }
+
+               ret = aul_sock_send_bundle(client->pid, client->uid,
+                               APP_COM_MESSAGE, envelope, AUL_SOCK_NOREPLY);
+               if (ret < 0) {
+                       _E("failed to send message pid(%d), uid(%d), ret(%d)",
+                                       client->pid, client->uid, ret);
+               }
+       }
+
+       return AUL_APP_COM_R_ERROR_OK;
+}
+
+static void __remove_client(struct endpoint_info *info, int cpid)
+{
+       GList *client_head;
+       struct client_info *client;
+
+       if (info == NULL)
+               return;
+
+       client_head = info->clients;
+       while (client_head) {
+               client = (struct client_info *)client_head->data;
+               client_head = client_head->next;
+               if (client && client->pid == cpid) {
+                       info->clients = g_list_remove(info->clients, client);
+                       if (client->filter)
+                               g_free(client->filter);
+
+                       g_free(client);
+               }
+       }
+
+       if (info->clients == NULL) {
+               g_hash_table_remove(endpoint_tbl, info->endpoint);
+               _D("endpoint removed: %s", info->endpoint);
+               __free_endpoint(info);
+       }
+}
+
+static int __app_com_leave(const char *endpoint, int cpid)
+{
+       struct endpoint_info *info;
+       GList *endpoint_head;
+
+       info = g_hash_table_lookup(endpoint_tbl, endpoint);
+       if (!info) {
+               _E("endpoint not exists: %s", endpoint);
+               return AUL_APP_COM_R_ERROR_UNKNOWN_ENDPOINT;
+       }
+
+       endpoint_head = g_hash_table_lookup(cpid_tbl, GINT_TO_POINTER(cpid));
+       if (endpoint_head) {
+               endpoint_head = g_list_remove(endpoint_head, info);
+               if (endpoint_head == NULL) {
+                       g_hash_table_remove(cpid_tbl, GINT_TO_POINTER(cpid));
+               } else {
+                       g_hash_table_replace(cpid_tbl, GINT_TO_POINTER(cpid),
+                                       endpoint_head);
+               }
+       }
+       __remove_client(info, cpid);
+
+       return AUL_APP_COM_R_ERROR_OK;
+}
+
+int _app_com_client_remove(int cpid)
+{
+       GList *client_list;
+       struct endpoint_info *info;
+       GList *client_head;
+
+       client_list = g_hash_table_lookup(cpid_tbl, GINT_TO_POINTER(cpid));
+       if (client_list == NULL)
+               return AUL_APP_COM_R_OK;
+
+       client_head = g_list_first(client_list);
+       while (client_head) {
+               info = (struct endpoint_info *)client_head->data;
+               client_head = g_list_next(client_head);
+               if (info) {
+                       client_list = g_list_remove(client_list, info);
+                       __remove_client(info, cpid);
+               }
+       }
+
+       g_hash_table_remove(cpid_tbl, GINT_TO_POINTER(cpid));
+
+       return AUL_APP_COM_R_ERROR_OK;
+}
+
+bool _app_com_endpoint_exists(const char *endpoint)
+{
+       return g_hash_table_contains(endpoint_tbl, endpoint);
+}
+
+static int __dispatch_app_com_create(request_h req)
+{
+       bundle *kb;
+       int ret;
+       size_t propagate_size;
+       unsigned int propagate = 0;
+       const char *privilege;
+       const char *endpoint;
+       unsigned int *prop;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       endpoint = bundle_get_val(kb, AUL_K_COM_ENDPOINT);
+       if (endpoint == NULL) {
+               _request_send_result(req, AUL_APP_COM_R_ERROR_FATAL_ERROR);
+               return 0;
+       }
+
+       privilege = bundle_get_val(kb, AUL_K_COM_PRIVILEGE);
+       if (!privilege) {
+               /* privilege is not mandatory so far */
+               _D("non-privileged endpoint: %s", endpoint);
+       }
+
+       ret = bundle_get_byte(kb, AUL_K_COM_PROPAGATE, (void **)&prop,
+                       &propagate_size);
+       if (ret == 0)
+               propagate = *prop;
+
+       _D("endpoint: %s propagate: %x privilege: %s",
+                       endpoint, propagate, privilege);
+
+       ret = __app_com_add_endpoint(endpoint, propagate, privilege);
+       if (ret == AUL_APP_COM_R_ERROR_OK ||
+                       ret == AUL_APP_COM_R_ERROR_ENDPOINT_ALREADY_EXISTS) {
+               ret = __app_com_join(endpoint, getpgid(_request_get_pid(req)), NULL,
+                               _request_get_uid(req));
+               if (ret == AUL_APP_COM_R_ERROR_ILLEGAL_ACCESS) {
+                       _E("illegal access: remove endpoint");
+                       __app_com_remove_endpoint(endpoint);
+               }
+       }
+
+       _request_send_result(req, ret);
+       return 0;
+}
+
+static int __dispatch_app_com_join(request_h req)
+{
+       bundle *kb;
+       int ret;
+       const char *endpoint;
+       const char *filter;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       endpoint = bundle_get_val(kb, AUL_K_COM_ENDPOINT);
+       if (endpoint == NULL) {
+               bundle_free(kb);
+               _request_send_result(req, AUL_APP_COM_R_ERROR_FATAL_ERROR);
+               return 0;
+       }
+
+       filter = bundle_get_val(kb, AUL_K_COM_FILTER);
+
+       ret = __app_com_join(endpoint, getpgid(_request_get_pid(req)), filter,
+                       _request_get_uid(req));
+
+       _request_send_result(req, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_com_send(request_h req)
+{
+       bundle *kb;
+       int ret;
+       const char *endpoint;
+       int sender_pid = _request_get_pid(req);
+       char sender_pid_str[MAX_PID_STR_BUFSZ];
+       uid_t sender_uid = _request_get_uid(req);
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       snprintf(sender_pid_str, MAX_PID_STR_BUFSZ, "%d", sender_pid);
+       bundle_del(kb, AUL_K_COM_SENDER_PID);
+       bundle_add(kb, AUL_K_COM_SENDER_PID, sender_pid_str);
+       endpoint = bundle_get_val(kb, AUL_K_COM_ENDPOINT);
+       if (endpoint == NULL) {
+               _request_send_result(req, AUL_APP_COM_R_ERROR_FATAL_ERROR);
+               return 0;
+       }
+
+       ret = _app_com_send(endpoint, getpgid(sender_pid), kb, sender_uid);
+       _request_send_result(req, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_com_leave(request_h req)
+{
+       bundle *kb;
+       int ret;
+       const char *endpoint;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       endpoint = bundle_get_val(kb, AUL_K_COM_ENDPOINT);
+       if (endpoint == NULL) {
+               _request_send_result(req, AUL_APP_COM_R_ERROR_FATAL_ERROR);
+               return 0;
+       }
+
+       ret = __app_com_leave(endpoint, getpgid(_request_get_pid(req)));
+       _request_send_result(req, ret);
+
+       return 0;
+}
+
+static request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = APP_COM_CREATE,
+               .callback = __dispatch_app_com_create
+       },
+       {
+               .cmd = APP_COM_JOIN,
+               .callback = __dispatch_app_com_join
+       },
+       {
+               .cmd = APP_COM_SEND,
+               .callback = __dispatch_app_com_send
+       },
+       {
+               .cmd = APP_COM_LEAVE,
+               .callback = __dispatch_app_com_leave
+       },
+};
+
+static int __com_create_checker(caller_info_h info, request_h req,
+               void *data)
+{
+       char *privilege = NULL;
+       bundle *kb = _request_get_bundle(req);
+
+       bundle_get_str(kb, AUL_K_COM_PRIVILEGE, &privilege);
+       if (!privilege)
+               return 0;
+
+       return _cynara_simple_checker(info, req, privilege);
+}
+
+static int __com_join_checker(caller_info_h info, request_h req,
+               void *data)
+{
+       char *endpoint = NULL;
+       const char *privilege;
+       bundle *kb = _request_get_bundle(req);
+
+       bundle_get_str(kb, AUL_K_COM_ENDPOINT, &endpoint);
+       if (!endpoint)
+               return -1;
+
+       privilege = _app_com_get_privilege(endpoint);
+       if (!privilege)
+               return 0;
+
+       return _cynara_simple_checker(info, req, (void *)privilege);
+}
+
+static cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = APP_COM_JOIN,
+               .checker = __com_create_checker,
+               .data = NULL
+       },
+       {
+               .cmd = APP_COM_CREATE,
+               .checker = __com_join_checker,
+               .data = NULL
+       },
+};
+
+int _app_com_broker_init(void)
+{
+       int r;
+
+       if (!endpoint_tbl) {
+               endpoint_tbl = g_hash_table_new(g_str_hash, g_str_equal);
+               if (endpoint_tbl == NULL) {
+                       _E("out of memory");
+                       return -1;
+               }
+       }
+
+       if (!cpid_tbl) {
+               cpid_tbl = g_hash_table_new(g_direct_hash, g_direct_equal);
+               if (cpid_tbl == NULL) {
+                       _E("out of memory");
+                       return -1;
+               }
+       }
+
+       r = _request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               _E("Failed to register cmds");
+               return -1;
+       }
+
+       r = _cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (r < 0) {
+               _E("Failed to register checkers");
+               return -1;
+       }
+
+       return 0;
+}
+
+int _app_com_broker_fini(void)
+{
+       if (cpid_tbl) {
+               g_hash_table_foreach(cpid_tbl, __remove_cpid, NULL);
+               g_hash_table_destroy(cpid_tbl);
+               cpid_tbl = NULL;
+       }
+
+       if (endpoint_tbl) {
+               g_hash_table_destroy(endpoint_tbl);
+               endpoint_tbl = NULL;
+       }
+
+       return 0;
+}
diff --git a/src/lib/amd_app_property.c b/src/lib/amd_app_property.c
new file mode 100644 (file)
index 0000000..4d348c4
--- /dev/null
@@ -0,0 +1,1152 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+#include <ctype.h>
+#include <gio/gio.h>
+#include <aul_svc.h>
+#include <pkgmgr-info.h>
+#include <aul_sock.h>
+#include <aul.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+
+#include "amd_util.h"
+#include "amd_app_property.h"
+#include "amd_request.h"
+#include "amd_appinfo.h"
+#include "amd_cynara.h"
+
+struct metadata_filter {
+       const char *key;
+       const char *value; /* Could be NULL */
+};
+
+struct metadata_entity {
+       char *appid;
+       char *key;
+       char *value;
+};
+
+struct app_property_s {
+       uid_t uid;
+       GHashTable *alias_info_table;
+       GHashTable *allowed_info_table;
+       GHashTable *appid_cache_table;
+       GList *metadata_list;
+};
+
+static GHashTable *user_prop_table;
+
+static int __foreach_allowed_info(const char *appid, const char *allowed_appid,
+               void *data);
+
+static int __add_alias_info(const char *alias_appid,
+               const char *appid, void *user_data)
+{
+       GHashTable *alias_info_table = (GHashTable *)user_data;
+       char *key;
+       char *value;
+       char *id;
+
+       if (alias_appid == NULL || appid == NULL || alias_info_table == NULL) {
+               _W("Invalid parameter");
+               return -1;
+       }
+
+       key = strdup(alias_appid);
+       if (key == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       value = strdup(appid);
+       if (value == NULL) {
+               _E("out of memory");
+               free(key);
+               return -1;
+       }
+
+       id = g_hash_table_lookup(alias_info_table, key);
+       if (id) {
+               _D("Replace alias info - alias_appid(%s), appid(%s)",
+                               key, value);
+               g_hash_table_replace(alias_info_table, key, value);
+       } else {
+               g_hash_table_insert(alias_info_table, key, value);
+       }
+
+       return 0;
+}
+
+int _app_property_add_alias_info(app_property_h app_property,
+               const char *alias_appid, const char *appid)
+{
+       int ret;
+
+       if (app_property == NULL || appid == NULL) {
+               _W("Invalid parameter");
+               return -1;
+       }
+
+       if (alias_appid && appid) {
+               ret = __add_alias_info(alias_appid, appid,
+                               app_property->alias_info_table);
+               if (ret < 0) {
+                       _W("Failed to add alias info");
+                       return -1;
+               }
+       } else if (appid) {
+               ret = aul_svc_foreach_alias_info_by_appid_for_uid(
+                               __add_alias_info, appid,
+                               app_property->uid,
+                               app_property->alias_info_table);
+               if (ret < 0) {
+                       _W("Failed to retrive alias info - appid(%s)", appid);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static gboolean __remove_alias_info(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       if (value == NULL || user_data == NULL) {
+               _W("Invalid parameter");
+               return FALSE;
+       }
+
+       if (strcmp(value, user_data) == 0)
+               return TRUE;
+
+       return FALSE;
+}
+
+int _app_property_remove_alias_info(app_property_h app_property,
+               const char *alias_appid, const char *appid)
+{
+       const char *id;
+
+       if (app_property == NULL || (alias_appid == NULL && appid == NULL)) {
+               _W("Invalid parameter");
+               return -1;
+       }
+
+       if (alias_appid) {
+               id = g_hash_table_lookup(app_property->alias_info_table,
+                               alias_appid);
+               if (id) {
+                       g_hash_table_remove(app_property->alias_info_table,
+                                       alias_appid);
+               }
+       } else {
+               g_hash_table_foreach_remove(app_property->alias_info_table,
+                               __remove_alias_info, (gpointer)appid);
+       }
+
+       return 0;
+}
+
+const char *_app_property_get_real_appid(app_property_h app_property,
+               const char *alias_appid)
+{
+       if (app_property == NULL || alias_appid == NULL) {
+               _W("Invalid parameter");
+               return NULL;
+       }
+
+       return g_hash_table_lookup(app_property->alias_info_table, alias_appid);
+}
+
+GList *_app_property_get_allowed_app_list(app_property_h app_property,
+               const char *appid)
+{
+       if (app_property == NULL || appid == NULL) {
+               _W("Invalid parameter");
+               return NULL;
+       }
+
+       return g_hash_table_lookup(app_property->allowed_info_table, appid);
+}
+
+app_property_h _app_property_find(uid_t uid)
+{
+       if (user_prop_table == NULL)
+               return NULL;
+
+       return g_hash_table_lookup(user_prop_table, GUINT_TO_POINTER(uid));
+}
+
+int _app_property_insert(uid_t uid, const char *appid)
+{
+       int ret;
+       app_property_h app_property;
+
+       if (appid == NULL) {
+               _W("Invalid parameter");
+               return -1;
+       }
+
+       app_property = _app_property_find(uid);
+       if (app_property == NULL)
+               return -1;
+
+       ret = aul_svc_foreach_alias_info_by_appid_for_uid(__add_alias_info,
+                       appid, app_property->uid,
+                       app_property->alias_info_table);
+       if (ret < 0) {
+               _E("Failed to retrive alias info uid(%d) - ret(%d)",
+                               app_property->uid, ret);
+               return -1;
+       }
+
+       ret = aul_svc_foreach_allowed_info_by_appid_for_uid(
+                       __foreach_allowed_info, appid,
+                       app_property->uid, app_property->allowed_info_table);
+       if (ret < 0) {
+               _E("Failed to retrive allowed info uid(%d) - ret (%d)",
+                               app_property->uid, ret);
+               return -1;
+       }
+
+       _D("uid(%d), appid(%s)", uid, appid);
+
+       return 0;
+}
+
+int _app_property_delete(uid_t uid, const char *appid)
+{
+       app_property_h app_property;
+
+       if (appid == NULL) {
+               _W("Invalid parameter");
+               return -1;
+       }
+
+       app_property = _app_property_find(uid);
+       if (app_property == NULL)
+               return -1;
+
+       g_hash_table_foreach_remove(app_property->alias_info_table,
+                       __remove_alias_info, (gpointer)appid);
+
+       g_hash_table_remove(app_property->allowed_info_table, appid);
+       _D("uid(%d), appid(%s)", uid, appid);
+
+       return 0;
+}
+
+static void __foreach_alias_info(const char *alias_appid, const char *appid,
+               void *data)
+{
+       GHashTable *alias_info_table = (GHashTable *)data;
+       char *key;
+       char *value;
+
+       if (alias_appid == NULL || appid == NULL || alias_info_table == NULL) {
+               _W("Invalid parameter");
+               return;
+       }
+
+       key = strdup(alias_appid);
+       if (key == NULL) {
+               _E("out of memory");
+               return;
+       }
+
+       value = strdup(appid);
+       if (value == NULL) {
+               _E("out of memory");
+               free(key);
+               return;
+       }
+
+       g_hash_table_insert(alias_info_table, key, value);
+}
+
+static int __foreach_allowed_info(const char *appid, const char *allowed_appid,
+               void *data)
+{
+       GHashTable *allowed_info_table = (GHashTable *)data;
+       char *key;
+       char *value;
+       GList *list;
+
+       if (appid == NULL || allowed_appid == NULL ||
+                       allowed_info_table == NULL) {
+               _W("Invalid parameter");
+               return -1;
+       }
+
+       value = strdup(allowed_appid);
+       if (value == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       list = g_hash_table_lookup(allowed_info_table, appid);
+       if (list) {
+               list = g_list_append(list, value);
+       } else {
+               key = strdup(appid);
+               if (key == NULL) {
+                       _E("out of memory");
+                       free(value);
+                       return -1;
+               }
+
+               list = g_list_append(list, value);
+               g_hash_table_insert(allowed_info_table, key, list);
+       }
+
+       return 0;
+}
+
+static void __destroy_allowed_info_list(gpointer data)
+{
+       GList *list = (GList *)data;
+
+       if (list == NULL)
+               return;
+
+       g_list_free_full(list, free);
+}
+
+static struct app_property_s *__create_app_property(uid_t uid)
+{
+       struct app_property_s *prop;
+
+       prop = calloc(1, sizeof(struct app_property_s));
+       if (prop == NULL) {
+               _E("out of memory");
+               return NULL;
+       }
+
+       prop->uid = uid;
+       prop->alias_info_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                       free, free);
+       if (prop->alias_info_table == NULL) {
+               _E("Failed to create alias info table");
+               free(prop);
+               return NULL;
+       }
+
+       prop->allowed_info_table = g_hash_table_new_full(g_str_hash,
+                       g_str_equal, free, __destroy_allowed_info_list);
+       if (prop->allowed_info_table == NULL) {
+               _E("Failed to create allowed info table");
+               g_hash_table_destroy(prop->alias_info_table);
+               free(prop);
+               return NULL;
+       }
+
+       prop->appid_cache_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                       free, free);
+       if (prop->appid_cache_table == NULL) {
+               _E("Failed to create appid cache table");
+               g_hash_table_destroy(prop->allowed_info_table);
+               g_hash_table_destroy(prop->alias_info_table);
+               free(prop);
+               return NULL;
+       }
+
+       prop->metadata_list = NULL;
+
+       return prop;
+}
+
+static void __free_metadata_entity(gpointer data)
+{
+       struct metadata_entity *entity = data;
+
+       if (!entity)
+               return;
+
+       free(entity->appid);
+       free(entity->key);
+       free(entity->value);
+       free(entity);
+}
+
+static void __destroy_app_property(gpointer data)
+{
+       struct app_property_s *prop = (struct app_property_s *)data;
+
+       if (prop == NULL)
+               return;
+
+       if (prop->allowed_info_table)
+               g_hash_table_destroy(prop->allowed_info_table);
+       if (prop->alias_info_table)
+               g_hash_table_destroy(prop->alias_info_table);
+       if (prop->appid_cache_table)
+               g_hash_table_destroy(prop->appid_cache_table);
+       if (prop->metadata_list)
+               g_list_free_full(prop->metadata_list, __free_metadata_entity);
+
+       free(prop);
+}
+
+static gint __comp_metadata_list(gconstpointer a, gconstpointer b)
+{
+       const struct metadata_entity *entity1 = a;
+       const struct metadata_entity *entity2 = b;
+
+       if (!a || !b)
+               return -1;
+
+       if (!strcmp(entity1->appid, entity2->appid) &&
+                       !strcmp(entity1->key, entity2->key) &&
+                       !strcmp(entity1->value, entity2->value))
+               return 0;
+
+       return -1;
+}
+
+static void __add_metadata_info(const char *appid, const char *key,
+               const char *val, struct app_property_s *prop)
+{
+       struct metadata_entity *entity;
+       GList *found;
+
+       if (appid == NULL || key == NULL) {
+               _W("Invalid parameter");
+               return;
+       }
+
+       entity = calloc(1, sizeof(struct metadata_entity));
+       if (entity == NULL) {
+               _E("out of memory");
+               return;
+       }
+
+       entity->appid = strdup(appid);
+       if (!entity->appid) {
+               _E("out of memory");
+               goto err;
+       }
+
+       entity->key = strdup(key);
+       if (!entity->key) {
+               _E("out of memory");
+               goto err;
+       }
+
+       if (val) {
+               entity->value = strdup(val);
+               if (!entity->value) {
+                       _E("out of memory");
+                       goto err;
+               }
+       }
+
+       found = g_list_find_custom(prop->metadata_list, entity,
+                       __comp_metadata_list);
+       if (found)
+               goto err;
+
+       prop->metadata_list = g_list_append(prop->metadata_list, entity);
+       return;
+
+err:
+       free(entity->appid);
+       free(entity->key);
+       free(entity->value);
+       free(entity);
+}
+
+static struct metadata_filter __metadata_table[] = {
+       { METADATA_LARGEMEMORY, NULL },
+       { METADATA_OOMTERMINATION, NULL },
+};
+
+static int __app_list_cb(pkgmgrinfo_appinfo_h handle, void *user_data)
+{
+       char *appid = NULL;
+       struct app_property_s *prop = user_data;
+       char *val;
+       int ret;
+       int i;
+       const int n = ARRAY_SIZE(__metadata_table);
+
+       pkgmgrinfo_appinfo_get_appid(handle, &appid);
+       if (!appid)
+               return -1;
+
+       for (i = 0; i < n; i++) {
+               val = NULL;
+               ret = pkgmgrinfo_appinfo_get_metadata_value(handle,
+                               __metadata_table[i].key, &val);
+               if (ret == PMINFO_R_OK) {
+                       __add_metadata_info(appid, __metadata_table[i].key,
+                                       val, prop);
+               }
+       }
+
+       return 0;
+}
+
+static int __load_metadata(struct app_property_s *prop)
+{
+       int ret;
+       pkgmgrinfo_appinfo_metadata_filter_h handle;
+       int i;
+       const int n = ARRAY_SIZE(__metadata_table);
+
+       ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
+       if (ret != PMINFO_R_OK)
+               return -1;
+
+       for (i = 0; i < n; i++) {
+               ret = pkgmgrinfo_appinfo_metadata_filter_add(handle,
+                               __metadata_table[i].key,
+                               __metadata_table[i].value);
+               if (ret != PMINFO_R_OK) {
+                       pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+                       return -1;
+               }
+       }
+
+       ret = pkgmgrinfo_appinfo_usr_metadata_filter_foreach(handle,
+                       __app_list_cb, prop, prop->uid);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+               return -1;
+       }
+
+       ret = pkgmgrinfo_appinfo_usr_metadata_filter_foreach(handle,
+                       __app_list_cb, prop, GLOBAL_USER);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+               return -1;
+       }
+
+       pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+
+       return 0;
+}
+
+static int __load_app_property(struct app_property_s *prop)
+{
+       int ret;
+
+       if (prop == NULL) {
+               _W("Invalid parameter");
+               return -1;
+       }
+
+       ret = aul_svc_foreach_alias_info_for_uid(__foreach_alias_info,
+                       prop->uid, prop->alias_info_table);
+       if (ret < 0) {
+               _E("Failed to retrive alias info uid(%d) - ret(%d)",
+                               prop->uid, ret);
+               return -1;
+       }
+
+       ret = aul_svc_foreach_allowed_info_for_uid(__foreach_allowed_info,
+                       prop->uid, prop->allowed_info_table);
+       if (ret < 0) {
+               _E("Failed to retrive allowed info uid(%d) - ret(%d)",
+                               prop->uid, ret);
+               return -1;
+       }
+
+       ret = __load_metadata(prop);
+       if (ret < 0) {
+               _E("Failed to retrive metadata info uid(%d) - ret(%d)",
+                               prop->uid, ret);
+               return -1;
+       }
+
+       return 0;
+}
+
+int _app_property_load(uid_t uid)
+{
+       int ret;
+       struct app_property_s *prop;
+
+       prop = __create_app_property(uid);
+       if (prop == NULL)
+               return -1;
+
+       ret = __load_app_property(prop);
+       if (ret < 0) {
+               _E("Failed to load properties - ret(%d)", ret);
+               __destroy_app_property(prop);
+               return -1;
+       }
+
+       g_hash_table_insert(user_prop_table, GUINT_TO_POINTER(uid), prop);
+
+       return 0;
+}
+
+void _app_property_unload(uid_t uid)
+{
+       g_hash_table_remove(user_prop_table, GUINT_TO_POINTER(uid));
+}
+
+static void __app_property_cache_put(app_property_h app_property,
+               const char *checksum, const char *appid)
+{
+       if (!app_property || !checksum || !appid)
+               return;
+
+       g_hash_table_replace(app_property->appid_cache_table, strdup(checksum),
+                       strdup(appid));
+}
+
+static const char *__app_property_cache_get(app_property_h app_property,
+               const char *checksum)
+{
+       if (!app_property || !checksum)
+               return NULL;
+
+       return g_hash_table_lookup(app_property->appid_cache_table, checksum);
+}
+
+void _app_property_cache_invalidate(app_property_h app_property)
+{
+       if (app_property)
+               g_hash_table_remove_all(app_property->appid_cache_table);
+}
+
+bool _app_property_metadata_query_bool(app_property_h app_property,
+               const char *appid, const char *key)
+{
+       return _app_property_metadata_match(app_property, appid, key, "true");
+}
+
+int _app_property_metadata_foreach(app_property_h app_property,
+               const char *appid, const char *key,
+               int (*callback)(const char *value, void *data),
+               void *user_data)
+{
+       struct metadata_entity *ret;
+       GList *i;
+
+       if (!app_property || !appid || !key)
+               return -1;
+
+       i = app_property->metadata_list;
+       while (i) {
+               ret = i->data;
+
+               if (!strcmp(ret->appid, appid) &&
+                       strcmp(ret->key, key)) {
+                       if (callback(ret->value, user_data) < 0)
+                               break;
+               }
+
+               i = g_list_next(i);
+       }
+
+       return 0;
+}
+
+bool _app_property_metadata_match(app_property_h app_property,
+               const char *appid, const char *key, const char *value)
+{
+       struct metadata_entity entity;
+       GList *i;
+
+       if (!app_property || !appid || !key || !value)
+               return false;
+
+       entity.appid = (char *)appid;
+       entity.key = (char *)key;
+       entity.value = (char *)value;
+       i = g_list_find_custom(app_property->metadata_list,
+                       &entity, __comp_metadata_list);
+       if (!i)
+               return false;
+
+       return true;
+}
+
+static gint __comp_key(gconstpointer a, gconstpointer b)
+{
+       const struct metadata_entity *entity1 = a;
+       const struct metadata_entity *entity2 = b;
+
+       if (!a || !b)
+               return -1;
+
+       if (!strcmp(entity1->appid, entity2->appid) &&
+                       !strcmp(entity1->key, entity2->key)) {
+               if (entity1->value && !strcmp(entity1->value, "false"))
+                       return -1;
+
+               return 0;
+       }
+
+       return -1;
+}
+
+bool _app_property_metadata_query_activation(app_property_h app_property,
+               const char *appid, const char *key)
+{
+       struct metadata_entity entity;
+       GList *i;
+
+       if (!app_property || !appid || !key)
+               return false;
+
+       entity.appid = (char *)appid;
+       entity.key = (char *)key;
+       entity.value = NULL;
+
+       i = g_list_find_custom(app_property->metadata_list,
+                       &entity, __comp_key);
+       if (!i)
+               return false;
+
+       return true;
+}
+
+static int __dispatch_app_set_alias_appid(request_h req)
+{
+       int ret;
+       const char *appid;
+       const char *alias_appid;
+       const struct appinfo *ai;
+       bundle *kb;
+       uid_t uid = _request_get_target_uid(req);
+       app_property_h app_property;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       alias_appid = bundle_get_val(kb, AUL_K_ALIAS_APPID);
+       if (alias_appid == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       if (appid == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ai = _appinfo_find(uid, appid);
+       if (ai == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = aul_svc_set_alias_appid_for_uid(alias_appid, appid, uid);
+       if (ret < 0) {
+               _E("Failed to set alias appid - alias_appid(%s), appid(%s)",
+                               alias_appid, appid);
+               _request_send_result(req, ret);
+               return -1;
+       }
+
+       app_property = _app_property_find(uid);
+       if (app_property == NULL) {
+               _E("Failed to find app property - uid(%d)", uid);
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = _app_property_add_alias_info(app_property, alias_appid, appid);
+       if (ret < 0) {
+               _E("Failed to add alias info - %s:%s", alias_appid, appid);
+               _request_send_result(req, ret);
+               return -1;
+       }
+
+       _request_send_result(req, 0);
+
+       return 0;
+}
+
+static int __dispatch_app_unset_alias_appid(request_h req)
+{
+       int ret;
+       const char *alias_appid;
+       bundle *kb;
+       uid_t uid = _request_get_target_uid(req);
+       app_property_h app_property;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       alias_appid = bundle_get_val(kb, AUL_K_ALIAS_APPID);
+       if (alias_appid == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = aul_svc_unset_alias_appid_for_uid(alias_appid, uid);
+       if (ret < 0) {
+               _E("Failed to unset alias appid - alias_appid(%s)",
+                               alias_appid);
+               _request_send_result(req, ret);
+               return -1;
+       }
+
+       app_property = _app_property_find(uid);
+       if (app_property == NULL) {
+               _E("Failed to find app property - uid(%d)", uid);
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = _app_property_remove_alias_info(app_property, alias_appid, NULL);
+       if (ret < 0) {
+               _E("Failed to remove alias info - %s", alias_appid);
+               _request_send_result(req, ret);
+               return -1;
+       }
+
+       _request_send_result(req, 0);
+
+       return 0;
+}
+
+static int __dispatch_app_enable_alias_info(request_h req)
+{
+       int ret;
+       const char *appid;
+       bundle *kb;
+       uid_t uid = _request_get_target_uid(req);
+       app_property_h app_property;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       if (appid == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = aul_svc_enable_alias_info_for_uid(appid, uid);
+       if (ret < 0) {
+               _E("Failed to activate alias info - appid(%s)", appid);
+               _request_send_result(req, ret);
+               return -1;
+       }
+
+       app_property = _app_property_find(uid);
+       if (app_property == NULL) {
+               _E("Failed to find app property - uid(%d)", uid);
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = _app_property_add_alias_info(app_property, NULL, appid);
+       if (ret < 0) {
+               _E("Failed to add alias info - %s", appid);
+               _request_send_result(req, ret);
+               return -1;
+       }
+
+       _request_send_result(req, 0);
+
+       return 0;
+}
+
+static int __dispatch_app_disable_alias_info(request_h req)
+{
+       int ret;
+       const char *appid;
+       bundle *kb;
+       uid_t uid = _request_get_target_uid(req);
+       app_property_h app_property;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       if (appid == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = aul_svc_disable_alias_info_for_uid(appid, uid);
+       if (ret < 0) {
+               _E("Failed to deactivate alias info - appid(%s)", appid);
+               _request_send_result(req, ret);
+               return -1;
+       }
+
+       app_property = _app_property_find(uid);
+       if (app_property == NULL) {
+               _E("Failed to find app property - uid(%d)", uid);
+               _request_send_result(req, -1);
+       }
+
+       ret = _app_property_remove_alias_info(app_property, NULL, appid);
+       if (ret < 0) {
+               _E("Failed to remove alias info - appid(%s)", appid);
+               _request_send_result(req, ret);
+               return -1;
+       }
+
+       _request_send_result(req, 0);
+
+       return 0;
+}
+
+static int __dispatch_app_set_app_control_default_app(request_h req)
+{
+       bundle *kb = NULL;
+       const char *op;
+       const char *mime_type;
+       const char *uri;
+       const char *appid;
+       int ret;
+       app_property_h prop;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       op = aul_svc_get_operation(kb);
+       appid = aul_svc_get_appid(kb);
+       if (op == NULL || appid == NULL) {
+               _E("Invalid operation, appid");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       mime_type = aul_svc_get_mime(kb);
+       uri = aul_svc_get_uri(kb);
+
+       ret = aul_svc_set_defapp_for_uid(op, mime_type, uri,
+                       appid, _request_get_target_uid(req));
+       if (ret < 0) {
+               _E("Error[%d], aul_svc_set_defapp", ret);
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       prop = _app_property_find(_request_get_target_uid(req));
+       _app_property_cache_invalidate(prop);
+       _request_send_result(req, 0);
+       return 0;
+}
+
+static int __dispatch_app_unset_app_control_default_app(request_h req)
+{
+       char appid[MAX_PACKAGE_STR_SIZE];
+       int ret;
+       app_property_h prop;
+
+       snprintf(appid, MAX_PACKAGE_STR_SIZE - 1, "%s",
+                       (const char *)_request_get_raw(req));
+
+       ret = aul_svc_unset_defapp_for_uid(appid, _request_get_target_uid(req));
+       if (ret < 0) {
+               _E("Error[%d], aul_svc_unset_defapp", ret);
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       prop = _app_property_find(_request_get_target_uid(req));
+       _app_property_cache_invalidate(prop);
+       _request_send_result(req, 0);
+       return 0;
+}
+
+static int __dispatch_app_get_appid_from_cache(request_h req)
+{
+       const char *checksum;
+       const char *appid;
+       bundle *b = _request_get_bundle(req);
+       app_property_h prop = _app_property_find(_request_get_target_uid(req));
+
+       checksum = bundle_get_val(b, AUL_K_CHECKSUM);
+       appid  = __app_property_cache_get(prop, checksum);
+
+       if (!appid) {
+               aul_sock_send_raw_with_fd(_request_remove_fd(req),
+                               APP_GET_APPID_FROM_CACHE, NULL, 0,
+                               AUL_SOCK_NOREPLY);
+               return 0;
+       }
+
+       aul_sock_send_raw_with_fd(_request_remove_fd(req),
+               APP_GET_APPID_FROM_CACHE, (unsigned char *)appid,
+               strlen(appid), AUL_SOCK_NOREPLY);
+
+       return 0;
+}
+
+static int __dispatch_app_set_cache(request_h req)
+{
+       const char *appid;
+       const char *checksum;
+       bundle *b = _request_get_bundle(req);
+       app_property_h prop = _app_property_find(_request_get_target_uid(req));
+
+       appid = bundle_get_val(b, AUL_K_APPID);
+       checksum = bundle_get_val(b, AUL_K_CHECKSUM);
+
+       if (!appid || !checksum) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       __app_property_cache_put(prop, checksum, appid);
+       _request_send_result(req, 0);
+       return 0;
+}
+
+static int __dispatch_app_invalidate_cache(request_h req)
+{
+       app_property_h prop = _app_property_find(_request_get_target_uid(req));
+
+       _app_property_cache_invalidate(prop);
+       _request_send_result(req, 0);
+       return 0;
+}
+
+static request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = APP_SET_ALIAS_APPID,
+               .callback = __dispatch_app_set_alias_appid
+       },
+       {
+               .cmd = APP_UNSET_ALIAS_APPID,
+               .callback = __dispatch_app_unset_alias_appid
+       },
+       {
+               .cmd = APP_ENABLE_ALIAS_INFO,
+               .callback = __dispatch_app_enable_alias_info
+       },
+       {
+               .cmd = APP_DISABLE_ALIAS_INFO,
+               .callback = __dispatch_app_disable_alias_info
+       },
+       {
+               .cmd = APP_SET_APP_CONTROL_DEFAULT_APP,
+               .callback = __dispatch_app_set_app_control_default_app
+       },
+       {
+               .cmd = APP_UNSET_APP_CONTROL_DEFAULT_APP,
+               .callback = __dispatch_app_unset_app_control_default_app
+       },
+       {
+               .cmd = APP_GET_APPID_FROM_CACHE,
+               .callback = __dispatch_app_get_appid_from_cache
+       },
+       {
+               .cmd = APP_SET_CACHE,
+               .callback = __dispatch_app_set_cache
+       },
+       {
+               .cmd = APP_INVALIDATE_CACHE,
+               .callback = __dispatch_app_invalidate_cache
+       },
+};
+
+static cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = APP_SET_APP_CONTROL_DEFAULT_APP,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_SYSTEM_SETTING
+       },
+       {
+               .cmd = APP_UNSET_APP_CONTROL_DEFAULT_APP,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_SYSTEM_SETTING
+       },
+       {
+               .cmd = APP_SET_ALIAS_APPID,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_SYSTEM_SETTING
+       },
+       {
+               .cmd = APP_UNSET_ALIAS_APPID,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_SYSTEM_SETTING
+       },
+       {
+               .cmd = APP_ENABLE_ALIAS_INFO,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_SYSTEM_SETTING
+       },
+       {
+               .cmd = APP_DISABLE_ALIAS_INFO,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_SYSTEM_SETTING
+       },
+};
+
+int _app_property_init(void)
+{
+       int r;
+
+       _D("app property init");
+
+       user_prop_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                       NULL, __destroy_app_property);
+       if (user_prop_table == NULL) {
+               _E("Failed to create user prop table");
+               return -1;
+       }
+
+       r = _request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               _E("Failed to register cmds");
+               return -1;
+       }
+
+       r = _cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (r < 0) {
+               _E("Failed to register checkers");
+               return -1;
+       }
+
+       return 0;
+}
+
+void _app_property_fini(void)
+{
+       _D("app property fini");
+
+       if (user_prop_table)
+               g_hash_table_destroy(user_prop_table);
+}
+
+
diff --git a/src/lib/amd_app_status.c b/src/lib/amd_app_status.c
new file mode 100644 (file)
index 0000000..458e557
--- /dev/null
@@ -0,0 +1,1998 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <aul.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <vconf.h>
+#include <time.h>
+#include <aul_sock.h>
+#include <aul_proc.h>
+#include <ctype.h>
+#include <gio/gio.h>
+#include <bundle_internal.h>
+
+#include "amd_app_status.h"
+#include "amd_appinfo.h"
+#include "amd_request.h"
+#include "amd_launch.h"
+#include "amd_util.h"
+#include "amd_suspend.h"
+#include "amd_socket.h"
+#include "amd_app_com.h"
+#include "amd_signal.h"
+#include "amd_noti.h"
+#include "amd_inotify.h"
+
+struct pkg_status_s {
+       char *pkgid;
+       int status;
+       GSList *ui_list;
+       GSList *svc_list;
+};
+
+struct app_status_s {
+       char *appid;
+       char *app_path;
+       char *pkgid;
+       char *instance_id;
+       int app_type;
+       int pid;
+       uid_t uid;
+       int status;
+       bool is_subapp;
+       int leader_pid;
+       int timestamp;
+       int fg_count;
+       bool managed;
+       int org_caller_pid;
+       int last_caller_pid;
+       struct pkg_status_s *pkg_status;
+       bool bg_launch;
+       bool socket_exists;
+       bool starting;
+       GHashTable *extras;
+       bool debug_mode;
+       guint timer;
+};
+
+static GSList *app_status_list;
+static GHashTable *pkg_status_table;
+static int limit_bg_uiapps;
+static char *home_appid;
+static GHashTable *__wd_table;
+
+static int __get_managed_uiapp_cnt(void)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+       int cnt = 0;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->managed &&
+                               app_status->app_type == AT_UI_APP)
+                       cnt++;
+       }
+
+       return cnt;
+}
+
+static void __cleanup_bg_uiapps(int n)
+{
+       GSList *iter;
+       GSList *iter_next;
+       struct app_status_s *app_status;
+       int i = 0;
+       int ret;
+
+       GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+               if (i == n)
+                       break;
+
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->status != STATUS_VISIBLE) {
+                       ret = _terminate_app_local(app_status->uid,
+                                       app_status->pid);
+                       if (ret < 0) {
+                               _E("Failed to terminate app(%d)",
+                                               app_status->pid);
+                               continue;
+                       }
+                       i++;
+               }
+       }
+}
+
+static void __check_running_uiapp_list(void)
+{
+       _noti_send("app_status.term_bg_apps", 0, 0, NULL, NULL);
+}
+
+int _app_status_term_bg_apps(GCompareFunc func)
+{
+       int len;
+       int n;
+
+       len = __get_managed_uiapp_cnt();
+       if (len <= 0)
+               return -1;
+
+       n = len - limit_bg_uiapps;
+       if (n <= 0)
+               return -1;
+
+       app_status_list = g_slist_sort(app_status_list, func);
+       __cleanup_bg_uiapps(n);
+
+       return 0;
+}
+
+static void __vconf_cb(keynode_t *key, void *data)
+{
+       const char *name;
+
+       name = vconf_keynode_get_name(key);
+       if (name && strcmp(name, VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS) == 0) {
+               limit_bg_uiapps = vconf_keynode_get_int(key);
+               if (limit_bg_uiapps > 0)
+                       __check_running_uiapp_list();
+       }
+}
+
+static void __update_leader_app_status(int leader_pid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+
+       if (leader_pid <= 0)
+               return;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->pid == leader_pid) {
+                       app_status->timestamp = time(NULL) / 10;
+                       app_status->fg_count++;
+                       break;
+               }
+       }
+}
+
+static void __add_pkg_status(struct app_status_s *app_status)
+{
+       struct pkg_status_s *pkg_status;
+
+       if (app_status == NULL) {
+               _E("Invalid parameter");
+               return;
+       }
+
+       if (app_status->app_type != AT_SERVICE_APP &&
+                       app_status->app_type != AT_UI_APP)
+               return;
+
+       if (pkg_status_table == NULL) {
+               pkg_status_table = g_hash_table_new(g_str_hash, g_str_equal);
+               if (pkg_status_table == NULL) {
+                       _E("out of memory");
+                       return;
+               }
+       }
+
+       pkg_status = g_hash_table_lookup(pkg_status_table, app_status->pkgid);
+       if (pkg_status == NULL) {
+               pkg_status = (struct pkg_status_s *)calloc(1,
+                               sizeof(struct pkg_status_s));
+               if (pkg_status == NULL) {
+                       _E("out of memory");
+                       return;
+               }
+
+               pkg_status->pkgid = strdup(app_status->pkgid);
+               if (pkg_status->pkgid == NULL) {
+                       _E("out of memory");
+                       free(pkg_status);
+                       return;
+               }
+
+               g_hash_table_insert(pkg_status_table, pkg_status->pkgid,
+                               pkg_status);
+       }
+
+       pkg_status->status = app_status->status;
+       app_status->pkg_status = pkg_status;
+
+       if (app_status->app_type == AT_SERVICE_APP) {
+               pkg_status->svc_list = g_slist_append(pkg_status->svc_list,
+                               app_status);
+       } else {
+               pkg_status->ui_list = g_slist_append(pkg_status->ui_list,
+                               app_status);
+       }
+}
+
+static int __get_ui_app_status_pkg_status(struct pkg_status_s *pkg_status)
+{
+       struct app_status_s *app_status;
+       GSList *iter;
+
+       for (iter = pkg_status->ui_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status->status != STATUS_BG)
+                       return app_status->status;
+       }
+
+       return STATUS_BG;
+}
+
+static int __update_pkg_status(struct app_status_s *app_status)
+{
+       struct pkg_status_s *pkg_status;
+       int ret;
+
+       if (app_status == NULL)
+               return -1;
+
+       if (pkg_status_table == NULL)
+               return -1;
+
+       pkg_status = (struct pkg_status_s *)g_hash_table_lookup(
+                       pkg_status_table, app_status->pkgid);
+       if (pkg_status == NULL) {
+               _E("pkgid(%s) is not on list", app_status->pkgid);
+               return -1;
+       }
+
+       if (pkg_status->ui_list) {
+               ret = __get_ui_app_status_pkg_status(pkg_status);
+               if (ret > -1)
+                       pkg_status->status = ret;
+       } else {
+               pkg_status->status = STATUS_SERVICE;
+       }
+
+       return 0;
+}
+
+static void __remove_pkg_status(struct app_status_s *app_status)
+{
+       struct pkg_status_s *pkg_status;
+
+       if (app_status == NULL) {
+               _E("Invalid parameter");
+               return;
+       }
+
+       pkg_status = g_hash_table_lookup(pkg_status_table, app_status->pkgid);
+       if (pkg_status == NULL)
+               return;
+
+       if (app_status->app_type == AT_SERVICE_APP) {
+               pkg_status->svc_list = g_slist_remove(pkg_status->svc_list,
+                               app_status);
+               _D("STATUS_SERVICE: appid(%s)", app_status->appid);
+       } else {
+               pkg_status->ui_list = g_slist_remove(pkg_status->ui_list,
+                               app_status);
+               _D("~STATUS_SERVICE: appid(%s)", app_status->appid);
+       }
+
+       if (!pkg_status->svc_list && !pkg_status->ui_list) {
+               g_hash_table_remove(pkg_status_table, pkg_status->pkgid);
+               if (pkg_status->pkgid)
+                       free(pkg_status->pkgid);
+               free(pkg_status);
+       }
+}
+
+static void __destroy_app_status(struct app_status_s *app_status)
+{
+       if (app_status == NULL)
+               return;
+
+       _noti_send("app_status.destroy", 0, 0, app_status, NULL);
+
+       if (app_status->instance_id)
+               free(app_status->instance_id);
+       if (app_status->pkgid)
+               free(app_status->pkgid);
+       if (app_status->app_path)
+               free(app_status->app_path);
+       if (app_status->appid)
+               free(app_status->appid);
+       if (app_status->extras)
+               g_hash_table_destroy(app_status->extras);
+       if (app_status->timer)
+               g_source_remove(app_status->timer);
+
+       free(app_status);
+}
+
+static int __get_app_type(const char *comp_type)
+{
+       if (comp_type == NULL)
+               return -1;
+
+       if (strcmp(comp_type, APP_TYPE_SERVICE) == 0)
+               return AT_SERVICE_APP;
+       else if (strcmp(comp_type, APP_TYPE_UI) == 0)
+               return AT_UI_APP;
+       else if (strcmp(comp_type, APP_TYPE_WIDGET) == 0)
+               return AT_WIDGET_APP;
+       else if (strcmp(comp_type, APP_TYPE_WATCH) == 0)
+               return AT_WATCH_APP;
+
+       return -1;
+}
+
+static int __app_status_set_app_info(struct app_status_s *app_status,
+               const struct appinfo *ai, int pid,
+               bool is_subapp, uid_t uid, int caller_pid,
+               bool bg_launch, const char *instance_id,
+               bool debug_mode)
+{
+       const char *appid;
+       const char *app_path;
+       const char *pkgid;
+       const char *comp_type;
+       const char *taskmanage;
+       char buf[MAX_PACKAGE_STR_SIZE];
+
+       appid = _appinfo_get_value(ai, AIT_NAME);
+       if (appid == NULL)
+               return -1;
+
+       app_status->appid = strdup(appid);
+       if (app_status->appid == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       app_path = _appinfo_get_value(ai, AIT_EXEC);
+       if (app_path == NULL)
+               return -1;
+
+       app_status->app_path = strdup(app_path);
+       if (app_status->app_path == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       pkgid = _appinfo_get_value(ai, AIT_PKGID);
+       if (pkgid == NULL)
+               return -1;
+
+       app_status->pkgid = strdup(pkgid);
+       if (app_status->pkgid == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+       if (comp_type == NULL)
+               return -1;
+
+       app_status->app_type = __get_app_type(comp_type);
+       if (app_status->app_type == -1) {
+               _E("Unknown component type: %s", comp_type);
+               return -1;
+       }
+
+       if (app_status->app_type == AT_SERVICE_APP)
+               app_status->status = STATUS_SERVICE;
+       else
+               app_status->status = STATUS_LAUNCHING;
+
+       if (instance_id) {
+               app_status->instance_id = strdup(instance_id);
+               if (app_status->instance_id == NULL) {
+                       _E("out of memory");
+                       return -1;
+               }
+       } else {
+               snprintf(buf, sizeof(buf), "%s:%d", appid, pid);
+               app_status->instance_id = strdup(buf);
+               if (app_status->instance_id == NULL) {
+                       _E("out of memory");
+                       return -1;
+               }
+       }
+
+       app_status->pid = pid;
+       app_status->uid = uid;
+       app_status->is_subapp = is_subapp;
+       app_status->timestamp = time(NULL) / 10;
+       app_status->org_caller_pid = caller_pid;
+       app_status->last_caller_pid = caller_pid;
+
+       taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE);
+       if (taskmanage && strcmp(taskmanage, "true") == 0 &&
+                       app_status->leader_pid > 0 &&
+                       app_status->is_subapp == false)
+               app_status->managed = true;
+
+       app_status->bg_launch = bg_launch;
+       app_status->socket_exists = false;
+       app_status->starting = false;
+       app_status->extras = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
+       app_status->debug_mode = debug_mode;
+
+       return 0;
+}
+
+int _app_status_set_extra(app_status_h app_status, const char *key, void *data)
+{
+       char *name;
+
+       if (!app_status || !app_status->extras)
+               return -1;
+
+       name = strdup(key);
+       if (!name)
+               return -1;
+
+       _app_status_remove_extra(app_status, key);
+       if (g_hash_table_insert(app_status->extras, name, data) == TRUE)
+               return 0;
+
+       return -1;
+}
+
+int _app_status_remove_extra(app_status_h app_status, const char *key)
+{
+       if (!app_status || !app_status->extras)
+               return -1;
+
+       if (g_hash_table_remove(app_status->extras, key) == TRUE)
+               return 0;
+
+       return -1;
+}
+
+void *_app_status_get_extra(app_status_h app_status, const char *key)
+{
+       if (!app_status || !app_status->extras)
+               return NULL;
+
+       return g_hash_table_lookup(app_status->extras, key);
+}
+
+int _app_status_add_app_info(const struct appinfo *ai, int pid,
+               bool is_subapp, uid_t uid, int caller_pid,
+               bool bg_launch, const char *instance_id,
+               bool debug_mode)
+{
+       GSList *iter;
+       GSList *iter_next;
+       struct app_status_s *app_status;
+       int r;
+
+       if (ai == NULL)
+               return -1;
+
+       GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->pid == pid) {
+                       if (app_status->uid == uid)
+                               return 0;
+
+                       app_status_list = g_slist_remove(app_status_list,
+                                       app_status);
+                       __remove_pkg_status(app_status);
+                       __destroy_app_status(app_status);
+                       break;
+               }
+       }
+
+       app_status = (struct app_status_s *)calloc(1,
+                       sizeof(struct app_status_s));
+       if (app_status == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       r = __app_status_set_app_info(app_status, ai, pid, is_subapp, uid,
+                       caller_pid, bg_launch, instance_id, debug_mode);
+       if (r < 0) {
+               __destroy_app_status(app_status);
+               return -1;
+       }
+
+       _noti_send("app_status.add", 0, 0, app_status, NULL);
+       app_status_list = g_slist_append(app_status_list, app_status);
+       __add_pkg_status(app_status);
+
+       return 0;
+}
+
+int _app_status_remove_all_app_info_with_uid(uid_t uid)
+{
+       GSList *iter;
+       GSList *iter_next;
+       struct app_status_s *app_status;
+
+       GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->uid == uid) {
+                       app_status_list = g_slist_remove(app_status_list,
+                                       app_status);
+                       __destroy_app_status(app_status);
+               }
+       }
+
+       return 0;
+}
+
+int _app_status_remove(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+       app_status_list = g_slist_remove(app_status_list, app_status);
+       __remove_pkg_status(app_status);
+       __destroy_app_status(app_status);
+
+       return 0;
+}
+
+static gboolean __terminate_timer_cb(gpointer data)
+{
+       int pid = GPOINTER_TO_INT(data);
+       app_status_h app_status;
+       int r;
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL)
+               return G_SOURCE_REMOVE;
+
+       _D("pid(%d)", pid);
+       r = kill(pid, SIGKILL);
+       if (r < 0)
+               _W("Failed to send SIGKILL, pid(%d), errno(%d)", pid, errno);
+       app_status->timer = 0;
+
+       return G_SOURCE_REMOVE;
+}
+
+int _app_status_update_status(app_status_h app_status, int status, bool force,
+               bool update_group_info)
+{
+       if (app_status == NULL || status < 0)
+               return -1;
+
+       _D("pid: %d, status: %d", app_status->pid, status);
+       _noti_send("app_status.update_status.start", status, 0,
+                       app_status, NULL);
+       if (app_status->status == STATUS_DYING) {
+               _E("%s is STATUS_DYING", app_status->appid);
+               return -1;
+       }
+
+       app_status->status = status;
+       if (app_status->status == STATUS_VISIBLE) {
+               app_status->timestamp = time(NULL) / 10;
+               app_status->fg_count++;
+               if (!app_status->managed)
+                       __update_leader_app_status(app_status->leader_pid);
+               if (app_status->fg_count == 1 && limit_bg_uiapps > 0)
+                       __check_running_uiapp_list();
+       } else if (app_status->status == STATUS_DYING) {
+               if (!app_status->debug_mode) {
+                       app_status->timer = g_timeout_add_seconds(5,
+                                       __terminate_timer_cb,
+                                       GINT_TO_POINTER(app_status->pid));
+               }
+       }
+
+       __update_pkg_status(app_status);
+       _D("pid: %d, appid: %s, pkgid: %s, status: %d",
+                       app_status->pid, app_status->appid, app_status->pkgid,
+                       app_status->status);
+       _noti_send("app_status.update_status.end", force, update_group_info,
+                       app_status, NULL);
+
+       return 0;
+}
+
+int _app_status_update_last_caller_pid(app_status_h app_status, int caller_pid)
+{
+       if (app_status == NULL)
+               return -1;
+
+       app_status->last_caller_pid = caller_pid;
+
+       return 0;
+}
+
+int _app_status_update_bg_launch(app_status_h app_status, bool bg_launch)
+{
+       if (app_status == NULL)
+               return -1;
+
+       if (!app_status->bg_launch)
+               return 0;
+
+       app_status->bg_launch = bg_launch;
+
+       return 0;
+}
+
+int _app_status_get_process_cnt(const char *appid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+       int cnt = 0;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->appid &&
+                               strcmp(app_status->appid, appid) == 0)
+                       cnt++;
+       }
+
+       return cnt;
+}
+
+bool _app_status_is_home_app(app_status_h app_status)
+{
+       const char *appid = _app_status_get_appid(app_status);
+
+       if (!appid)
+               return false;
+       if (!home_appid)
+               return false;
+
+       if (strcmp(home_appid, appid) == 0)
+               return true;
+
+       return false;
+}
+
+int _app_status_get_pid(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+       return app_status->pid;
+}
+
+int _app_status_get_org_caller_pid(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+       return app_status->org_caller_pid;
+}
+
+int _app_status_get_last_caller_pid(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+       return app_status->last_caller_pid;
+}
+
+int _app_status_is_running(app_status_h app_status)
+{
+       if (app_status == NULL ||
+               (app_status->app_type == AT_UI_APP && app_status->is_subapp))
+               return -1;
+
+       return app_status->pid;
+}
+
+int _app_status_get_status(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+       return app_status->status;
+}
+
+uid_t _app_status_get_uid(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return (uid_t)-1;
+
+       return app_status->uid;
+}
+
+const char *_app_status_get_appid(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return NULL;
+
+       return app_status->appid;
+}
+
+const char *_app_status_get_pkgid(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return NULL;
+
+       return app_status->pkgid;
+}
+
+bool _app_status_get_bg_launch(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return false;
+
+       return app_status->bg_launch;
+}
+
+const char *_app_status_get_instance_id(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return NULL;
+
+       return app_status->instance_id;
+}
+
+int _app_status_get_app_type(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+       return app_status->app_type;
+}
+
+bool _app_status_socket_exists(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return false;
+
+       return app_status->socket_exists;
+}
+
+bool _app_status_is_starting(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return false;
+
+       return app_status->starting;
+}
+
+int _app_status_update_is_starting(app_status_h app_status, bool is_starting)
+{
+       if (app_status == NULL)
+               return -1;
+
+       app_status->starting = is_starting;
+
+       return 0;
+}
+
+const char *_app_status_get_app_path(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return NULL;
+
+       return app_status->app_path;
+}
+
+app_status_h _app_status_find(int pid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->pid == pid)
+                       return app_status;
+       }
+
+       return NULL;
+}
+
+static int __read_ppid_from_proc(const char *path, int *ppid)
+{
+       FILE *fp;
+       int ret;
+       int result = -1;
+       char *buf = NULL;
+       int val;
+
+       if (path == NULL)
+               return -1;
+
+       fp = fopen(path, "r");
+       if (fp == NULL)
+               return -1;
+
+       ret = fscanf(fp, "%ms %d\n", &buf, &val);
+       while (ret != EOF) {
+               if (ret == 2) {
+                       if (buf && strcmp(buf, "PPid:") == 0) {
+                               *ppid = val;
+                               result = 0;
+                               _D("ppid : %d", *ppid);
+                               break;
+                       }
+               }
+
+               free(buf);
+               buf = NULL;
+               ret = fscanf(fp, "%ms %d\n", &buf, &val);
+       }
+
+       fclose(fp);
+       free(buf);
+
+       return result;
+}
+
+int __proc_get_ppid_by_pid(int pid)
+{
+       char path[PATH_MAX] = { 0, };
+       int ret = 0;
+       int ppid;
+
+       snprintf(path, sizeof(path), "/proc/%d/status", pid);
+       ret = __read_ppid_from_proc(path, &ppid);
+       if (ret < 0)
+               return -1;
+
+       return ppid;
+}
+
+app_status_h _app_status_find_v2(int pid)
+{
+       int ppid;
+       int pgid;
+       struct app_status_s *app_status;
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL) {
+               pgid = getpgid(pid);
+               if (pgid > 0)
+                       app_status = _app_status_find(pgid);
+       }
+
+       if (app_status == NULL) {
+               ppid = __proc_get_ppid_by_pid(pid);
+               app_status = _app_status_find(ppid);
+       }
+
+       return app_status;
+}
+
+app_status_h _app_status_find_by_appid(const char *appid, uid_t uid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->appid &&
+                               strcmp(app_status->appid, appid) == 0 &&
+                               app_status->uid == uid &&
+                               app_status->is_subapp == false)
+                       return app_status;
+       }
+
+       return NULL;
+}
+
+app_status_h _app_status_find_by_appid_v2(const char *appid, uid_t uid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->appid &&
+                               strcmp(app_status->appid, appid) == 0 &&
+                               app_status->uid == uid)
+                       return app_status;
+       }
+
+       return NULL;
+}
+
+app_status_h _app_status_find_with_org_caller(const char *appid, uid_t uid,
+               int caller_pid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->appid &&
+                               strcmp(app_status->appid, appid) == 0 &&
+                               app_status->uid == uid &&
+                               app_status->org_caller_pid == caller_pid)
+                       return app_status;
+       }
+
+       return NULL;
+}
+
+app_status_h _app_status_find_by_instance_id(const char *appid,
+               const char *instance_id, uid_t uid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->instance_id &&
+                               app_status->uid == uid &&
+                               !strcmp(app_status->instance_id, instance_id) &&
+                               !strcmp(app_status->appid, appid))
+                       return app_status;
+       }
+
+       return NULL;
+}
+
+void _app_status_find_service_apps(app_status_h app_status, int status,
+               void (*send_event_to_svc_core)(int, uid_t), bool suspend)
+{
+       GSList *iter;
+       GSList *svc_list = NULL;
+       const struct appinfo *ai;
+       struct app_status_s *svc_status;
+       bool bg_allowed;
+       uid_t uid;
+
+       if (app_status == NULL) {
+               _E("Invalid parameter");
+               return;
+       }
+
+       uid = _app_status_get_uid(app_status);
+       if (app_status->pkg_status && app_status->pkg_status->status == status)
+               svc_list = app_status->pkg_status->svc_list;
+
+       for (iter = svc_list; iter; iter = g_slist_next(iter)) {
+               svc_status = (struct app_status_s *)iter->data;
+               if (svc_status && svc_status->uid == uid) {
+                       ai = _appinfo_find(uid, svc_status->appid);
+                       bg_allowed = _suspend_is_allowed_background(ai);
+                       if (!bg_allowed) {
+                               send_event_to_svc_core(svc_status->pid, uid);
+                               if (suspend)
+                                       _suspend_add_timer(svc_status->pid);
+                               else
+                                       _suspend_remove_timer(svc_status->pid);
+                       }
+               }
+       }
+}
+
+void _app_status_check_service_only(app_status_h app_status,
+               void (*send_event_to_svc_core)(int, uid_t))
+{
+       GSList *iter;
+       GSList *ui_list = NULL;
+       struct app_status_s *ui_status;
+       int ui_cnt = 0;
+       bool bg_allowed;
+       const char *appid;
+       const struct appinfo *ai;
+       uid_t uid;
+
+       if (app_status == NULL) {
+               _E("Invalid parameter");
+               return;
+       }
+
+       uid = _app_status_get_uid(app_status);
+       if (app_status->pkg_status && app_status->pkg_status->ui_list)
+               ui_list = app_status->pkg_status->ui_list;
+
+       for (iter = ui_list; iter; iter = g_slist_next(iter)) {
+               ui_status = (struct app_status_s *)iter->data;
+               if (_app_status_get_status(ui_status) != STATUS_DYING)
+                       ui_cnt++;
+       }
+
+       if (ui_cnt == 0) {
+               appid = _app_status_get_appid(app_status);
+               ai = _appinfo_find(uid, appid);
+               bg_allowed = _suspend_is_allowed_background(ai);
+               if (!bg_allowed) {
+                       send_event_to_svc_core(app_status->pid, uid);
+                       _suspend_add_timer(app_status->pid);
+               }
+       }
+}
+
+static bundle *__create_appinfo_bundle(app_status_h app_status)
+{
+       bundle *b;
+       char tmp_str[MAX_PID_STR_BUFSZ];
+
+       b = bundle_create();
+       if (b == NULL)
+               return NULL;
+
+       snprintf(tmp_str, sizeof(tmp_str), "%d", app_status->pid);
+       bundle_add(b, AUL_K_PID, tmp_str);
+       bundle_add(b, AUL_K_APPID, app_status->appid);
+       bundle_add(b, AUL_K_EXEC, app_status->app_path);
+       bundle_add(b, AUL_K_PKGID, app_status->pkgid);
+       snprintf(tmp_str, sizeof(tmp_str), "%d", app_status->status);
+       bundle_add(b, AUL_K_STATUS, tmp_str);
+       snprintf(tmp_str, sizeof(tmp_str), "%d", app_status->is_subapp);
+       bundle_add(b, AUL_K_IS_SUBAPP, tmp_str);
+       if (app_status->instance_id)
+               bundle_add(b, AUL_K_INSTANCE_ID, app_status->instance_id);
+
+       return b;
+}
+
+static int __send_running_appinfo(app_status_h app_status, int fd)
+{
+       int ret;
+       bundle *b;
+       bundle_raw *raw = NULL;
+       int len = 0;
+
+       b = __create_appinfo_bundle(app_status);
+       if (b == NULL) {
+               _E("out of memory");
+               aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR,
+                               NULL, 0, AUL_SOCK_NOREPLY);
+               return -1;
+       }
+
+       ret = bundle_encode(b, &raw, &len);
+       bundle_free(b);
+       if (ret != BUNDLE_ERROR_NONE) {
+               _E("Failed to encode bundle");
+               aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR, NULL,
+                               0, AUL_SOCK_NOREPLY);
+               return -1;
+       }
+
+       ret = aul_sock_send_raw_with_fd(fd, APP_GET_INFO_OK,
+                       (unsigned char *)raw, len,
+                       AUL_SOCK_ASYNC | AUL_SOCK_BUNDLE);
+       if (ret < 0) {
+               _E("Failed to send raw data: %s", raw);
+               free(raw);
+               return ret;
+       }
+       free(raw);
+
+       return 0;
+}
+
+int _app_status_send_running_appinfo(int fd, int cmd, uid_t uid)
+{
+       GSList *list = NULL;
+       GSList *iter;
+       struct app_status_s *app_status;
+       int ret;
+       int count;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status->uid != uid ||
+                               app_status->status == STATUS_DYING)
+                       continue;
+               if (cmd != APP_ALL_RUNNING_INFO &&
+                               cmd != APP_RUNNING_INSTANCE_INFO &&
+                               (app_status->app_type == AT_UI_APP &&
+                                app_status->is_subapp))
+                       continue;
+               if (cmd == APP_RUNNING_INSTANCE_INFO &&
+                               app_status->instance_id == NULL)
+                       continue;
+
+               list = g_slist_append(list, app_status);
+       }
+
+       count = g_slist_length(list);
+       if (count == 0) {
+               _E("Applications are not running");
+               _send_result_to_client(fd, -1);
+               return -1;
+       }
+       _send_result_to_client_v2(fd, count);
+
+       for (iter = list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status == NULL)
+                       continue;
+
+               ret = __send_running_appinfo(app_status, fd);
+               if (ret < 0) {
+                       g_slist_free(list);
+                       return -1;
+               }
+       }
+       close(fd);
+       g_slist_free(list);
+
+       return 0;
+}
+
+int _app_status_foreach_running_appinfo(void (*callback)(app_status_h, void *),
+               void *data)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+
+       if (callback == NULL)
+               return -1;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status->status == STATUS_DYING ||
+                               app_status->is_subapp)
+                       continue;
+               callback(app_status, data);
+       }
+
+       return 0;
+}
+
+int _app_status_terminate_apps(const char *appid, uid_t uid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+       int ret;
+
+       if (appid == NULL)
+               return -1;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status->uid == uid &&
+                               strcmp(app_status->appid, appid) == 0 &&
+                               app_status->status != STATUS_DYING) {
+                       ret = _terminate_app_local(app_status->uid,
+                                       app_status->pid);
+                       if (ret < 0) {
+                               _E("Failed to terminate app(%d)",
+                                               app_status->pid);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int _app_status_terminate_apps_by_pkgid(const char *pkgid, uid_t uid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+       int ret;
+
+       if (pkgid == NULL)
+               return -1;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status->uid == uid &&
+                               strcmp(app_status->pkgid, pkgid) == 0 &&
+                               app_status->status != STATUS_DYING) {
+                       ret = _terminate_app_local(app_status->uid,
+                                       app_status->pid);
+                       if (ret < 0) {
+                               _E("Failed to terminate app(%d)",
+                                               app_status->pid);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int _app_status_get_appid_bypid(int fd, int pid)
+{
+       int cmd = APP_GET_INFO_ERROR;
+       int len = 0;
+       int pgid;
+       int ppid;
+       int ret;
+       char appid[MAX_PACKAGE_STR_SIZE] = {0,};
+       app_status_h app_status;
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL) {
+               pgid = getpgid(pid);
+               if (pgid > 0) {
+                       app_status = _app_status_find(pgid);
+                       if (app_status == NULL) {
+                               ppid = __proc_get_ppid_by_pid(pid);
+                               app_status = _app_status_find(ppid);
+                       }
+               }
+       }
+
+       if (app_status) {
+               snprintf(appid, sizeof(appid), "%s",
+                               _app_status_get_appid(app_status));
+               SECURE_LOGD("appid for %d is %s", pid, appid);
+               len = strlen(appid);
+               cmd = APP_GET_INFO_OK;
+       }
+
+       ret = aul_sock_send_raw_with_fd(fd, cmd, (unsigned char *)appid,
+                       len, AUL_SOCK_NOREPLY);
+
+       return ret;
+}
+
+int _app_status_get_pkgid_bypid(int fd, int pid)
+{
+       int cmd = APP_GET_INFO_ERROR;
+       int len = 0;
+       int pgid;
+       int ppid;
+       int ret;
+       char pkgid[MAX_PACKAGE_STR_SIZE] = {0,};
+       app_status_h app_status;
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL) {
+               pgid = getpgid(pid);
+               if (pgid > 0) {
+                       app_status = _app_status_find(pgid);
+                       if (app_status == NULL) {
+                               ppid = __proc_get_ppid_by_pid(pid);
+                               app_status = _app_status_find(ppid);
+                       }
+               }
+       }
+
+       if (app_status) {
+               snprintf(pkgid, sizeof(pkgid), "%s",
+                               _app_status_get_pkgid(app_status));
+               SECURE_LOGD("pkgid for %d is %s", pid, pkgid);
+               len = strlen(pkgid);
+               cmd = APP_GET_INFO_OK;
+       }
+
+       ret = aul_sock_send_raw_with_fd(fd, cmd, (unsigned char *)pkgid,
+                       len, AUL_SOCK_NOREPLY);
+
+       return ret;
+}
+
+int _app_status_get_instance_id_bypid(int fd, int pid)
+{
+       int cmd = APP_GET_INFO_ERROR;
+       int len = 0;
+       int ret;
+       const char *instance_id;
+       char buf[MAX_PACKAGE_STR_SIZE] = {0,};
+       app_status_h app_status;
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL) {
+               app_status = _app_status_find(getpgid(pid));
+               if (app_status == NULL) {
+                       app_status = _app_status_find(
+                                       __proc_get_ppid_by_pid(pid));
+               }
+       }
+
+       instance_id = _app_status_get_instance_id(app_status);
+       if (instance_id) {
+               snprintf(buf, sizeof(buf), "%s", instance_id);
+               SECURE_LOGD("pid(%d), instance-id(%s)", pid, instance_id);
+               len = strlen(buf);
+               cmd = APP_GET_INFO_OK;
+       }
+
+       ret = aul_sock_send_raw_with_fd(fd, cmd, (unsigned char *)buf, len,
+                       AUL_SOCK_NOREPLY);
+
+       return ret;
+}
+
+int _app_status_set_leader_pid(app_status_h app_status, int pid)
+{
+       if (app_status == NULL)
+               return -1;
+
+
+       app_status->leader_pid = pid;
+
+       return 0;
+}
+
+int _app_status_get_leader_pid(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+
+       return app_status->leader_pid;
+}
+
+int _app_status_get_fg_cnt(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+
+       return app_status->fg_count;
+}
+
+int _app_status_get_timestamp(app_status_h app_status)
+{
+       if (app_status == NULL)
+               return -1;
+
+
+       return app_status->timestamp;
+}
+
+static void __home_appid_vconf_cb(keynode_t *key, void *data)
+{
+       char *tmpstr;
+
+       tmpstr = vconf_keynode_get_str(key);
+       if (tmpstr == NULL)
+               return;
+
+       if (home_appid)
+               free(home_appid);
+       home_appid = strdup(tmpstr);
+}
+
+int _app_status_publish_status(int pid, int context_status)
+{
+       bundle *b;
+       char endpoint_system[MAX_LOCAL_BUFSZ];
+       char endpoint_user[MAX_LOCAL_BUFSZ];
+       bool endpoint_system_exists;
+       bool endpoint_user_exists;
+       char buf[MAX_PID_STR_BUFSZ];
+       app_status_h app_status;
+       const char *appid;
+       uid_t uid;
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL)
+               return -1;
+
+       appid = _app_status_get_appid(app_status);
+       uid = _app_status_get_uid(app_status);
+       snprintf(endpoint_user, sizeof(endpoint_user),
+                       "app_status_event:%s:%d", appid, uid);
+       snprintf(endpoint_system, sizeof(endpoint_system),
+                       "app_status_event:%s", appid);
+       endpoint_system_exists = _app_com_endpoint_exists(endpoint_system);
+       endpoint_user_exists = _app_com_endpoint_exists(endpoint_user);
+       if (!endpoint_system_exists && !endpoint_user_exists)
+               return -1;
+
+       b = __create_appinfo_bundle(app_status);
+       if (b == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       snprintf(buf, sizeof(buf), "%d", context_status);
+       bundle_add(b, "__CONTEXT_STATUS__", buf);
+       if (endpoint_system_exists)
+               _app_com_send(endpoint_system, pid, b, uid);
+       if (endpoint_user_exists)
+               _app_com_send(endpoint_user, pid, b, uid);
+       bundle_free(b);
+
+       return 0;
+}
+
+static void __terminate_widget_apps_by_org_caller(int caller_pid, uid_t uid)
+{
+       GSList *iter;
+       struct app_status_s *app_status;
+       int ret;
+
+       for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+               app_status = (struct app_status_s *)iter->data;
+               if ((app_status->app_type == AT_WIDGET_APP ||
+                               app_status->app_type == AT_WATCH_APP) &&
+                               app_status->uid == uid &&
+                               app_status->org_caller_pid == caller_pid &&
+                               app_status->status != STATUS_DYING) {
+                       ret = _terminate_app_local(app_status->uid,
+                                       app_status->pid);
+                       if (ret < 0) {
+                               _E("Failed to terminate app(%d)",
+                                               app_status->pid);
+                       }
+               }
+       }
+}
+
+void _app_status_cleanup(app_status_h app_status)
+{
+       int pid;
+       const char *instance_id;
+       uid_t uid;
+
+       if (app_status == NULL)
+               return;
+
+       pid = _app_status_get_pid(app_status);
+       uid = _app_status_get_uid(app_status);
+       _D("pid: %d, uid: %d", pid, uid);
+
+       _noti_send("app_status.cleanup", pid, uid, app_status, NULL);
+
+       instance_id = _app_status_get_instance_id(app_status);
+       if (instance_id == NULL)
+               instance_id = _app_status_get_appid(app_status);
+
+       __terminate_widget_apps_by_org_caller(pid, uid);
+       _app_com_client_remove(pid);
+       _suspend_remove_proc(pid);
+       _app_status_remove(app_status);
+       aul_send_app_terminated_signal(pid);
+}
+
+static bool __socket_monitor_cb(const char *event_name, void *data)
+{
+       app_status_h app_status;
+       int pid = -1;
+
+       if (event_name == NULL)
+               return true;
+
+       if (isdigit(*event_name))
+               pid = atoi(event_name);
+
+       if (pid > 1) {
+               _D("pid: %d", pid);
+               _request_reply_for_pending_request(pid);
+               app_status = _app_status_find(pid);
+               if (app_status) {
+                       app_status->socket_exists = true;
+                       app_status->starting = true;
+               }
+       }
+
+       return true;
+}
+
+int _app_status_usr_init(uid_t uid)
+{
+       int wd;
+       char buf[PATH_MAX];
+
+       wd = GPOINTER_TO_INT(g_hash_table_lookup(__wd_table,
+                               GUINT_TO_POINTER(uid)));
+       if (wd > 0) {
+               _D("Already exists");
+               return 0;
+       }
+
+       snprintf(buf, sizeof(buf), "/run/aul/apps/%d", uid);
+       wd = _inotify_add_watch(buf, IN_CREATE, __socket_monitor_cb, NULL);
+       if (wd < 0) {
+               _E("Failed to add a watch - uid(%d)", uid);
+               return -1;
+       }
+
+       g_hash_table_insert(__wd_table, GUINT_TO_POINTER(uid),
+                       GINT_TO_POINTER(wd));
+
+       return 0;
+}
+
+void _app_status_usr_fini(uid_t uid)
+{
+       int wd;
+       GSList *iter;
+       GSList *iter_next;
+       app_status_h app_status;
+
+       wd = GPOINTER_TO_INT(g_hash_table_lookup(__wd_table,
+                               GUINT_TO_POINTER(uid)));
+       if (wd > 0) {
+               _inotify_rm_watch(wd);
+               g_hash_table_remove(__wd_table, GUINT_TO_POINTER(uid));
+       } else {
+               _D("Watch fd doesn't exist - uid(%d)", uid);
+       }
+
+       GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+               app_status = (struct app_status_s *)iter->data;
+               if (app_status && app_status->uid == uid)
+                       _app_status_cleanup(app_status);
+       }
+}
+
+static int __dispatch_app_running_info(request_h req)
+{
+       int ret;
+
+       ret = _app_status_send_running_appinfo(_request_remove_fd(req),
+                       _request_get_cmd(req), _request_get_target_uid(req));
+       return ret;
+}
+
+static int __dispatch_app_all_running_info(request_h req)
+{
+       int ret;
+
+       ret = _app_status_send_running_appinfo(_request_remove_fd(req),
+                       _request_get_cmd(req), _request_get_target_uid(req));
+       return ret;
+}
+
+static int __dispatch_app_is_running(request_h req)
+{
+       const char *appid;
+       int ret;
+       app_status_h app_status;
+       bundle *b = _request_get_bundle(req);
+
+       if (b == NULL) {
+               _E("Failed to get bundle");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       appid = bundle_get_val(b, AUL_K_APPID);
+       if (appid == NULL) {
+               _E("Failed to get appid");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       app_status = _app_status_find_by_appid(appid,
+                       _request_get_target_uid(req));
+       ret = _app_status_is_running(app_status);
+       SECURE_LOGD("APP_IS_RUNNING : %s : %d", appid, ret);
+       _request_send_result(req, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_get_appid_by_pid(request_h req)
+{
+       int pid;
+       int ret;
+       const char *pid_str;
+       bundle *b = _request_get_bundle(req);
+
+       if (b == NULL) {
+               _E("Failed to get bundle");
+               aul_sock_send_raw_with_fd(_request_remove_fd(req),
+                               APP_GET_INFO_ERROR, NULL, 0, AUL_SOCK_NOREPLY);
+               return -1;
+       }
+
+       pid_str = bundle_get_val(b, AUL_K_PID);
+       if (pid_str == NULL || !isdigit(pid_str[0])) {
+               _E("Failed to get pid");
+               aul_sock_send_raw_with_fd(_request_remove_fd(req),
+                               APP_GET_INFO_ERROR, NULL, 0, AUL_SOCK_NOREPLY);
+               return -1;
+       }
+
+       pid = atoi(pid_str);
+       ret = _app_status_get_appid_bypid(_request_remove_fd(req), pid);
+       _D("app_status_get_appid_bypid : %d : %d", pid, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_get_pkgid_by_pid(request_h req)
+{
+       int pid;
+       int ret;
+       const char *pid_str;
+       bundle *b = _request_get_bundle(req);
+
+       if (b == NULL) {
+               _E("Failed to get bundle");
+               aul_sock_send_raw_with_fd(_request_remove_fd(req),
+                               APP_GET_INFO_ERROR, NULL, 0, AUL_SOCK_NOREPLY);
+               return -1;
+       }
+
+       pid_str = bundle_get_val(b, AUL_K_PID);
+       if (pid_str == NULL || !isdigit(pid_str[0])) {
+               _E("Failed to get pid");
+               aul_sock_send_raw_with_fd(_request_remove_fd(req),
+                               APP_GET_INFO_ERROR, NULL, 0, AUL_SOCK_NOREPLY);
+               return -1;
+       }
+
+       pid = atoi(pid_str);
+       ret = _app_status_get_pkgid_bypid(_request_remove_fd(req), pid);
+       _D("APP_GET_PKGID_BYPID : %d : %d", pid, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_status_update(request_h req)
+{
+       int *status;
+       const char *appid;
+       struct appinfo *ai;
+       app_status_h app_status;
+
+       app_status = _app_status_find(_request_get_pid(req));
+       if (app_status == NULL)
+               return -1;
+
+       status = (int *)_request_get_raw(req);
+       switch (*status) {
+       case STATUS_NORESTART:
+               appid = _app_status_get_appid(app_status);
+               ai = _appinfo_find(_request_get_target_uid(req), appid);
+               _appinfo_set_value((struct appinfo *)ai, AIT_STATUS,
+                               "norestart");
+               break;
+       case STATUS_VISIBLE:
+       case STATUS_BG:
+               break;
+       default:
+               _app_status_update_status(app_status, *status, false, true);
+               break;
+       }
+
+       return 0;
+}
+
+static int __dispatch_app_get_status(request_h req)
+{
+       int pid;
+       int status;
+       app_status_h app_status;
+       const char *pid_str;
+       bundle *b;
+
+       b = _request_get_bundle(req);
+       if (b == NULL) {
+               _E("Failed to get bundle");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       pid_str = bundle_get_val(b, AUL_K_PID);
+       if (pid_str == NULL || !isdigit(pid_str[0])) {
+               _E("Falied to get pid");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       pid = atoi(pid_str);
+       app_status = _app_status_find(pid);
+       status = _app_status_get_status(app_status);
+       _request_send_result(req, status);
+
+       return 0;
+}
+
+static int __dispatch_app_get_status_by_appid(request_h req)
+{
+       int status;
+       int pid;
+       uid_t uid;
+       const char *appid;
+       bundle *kb;
+       app_status_h app_status;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       uid = _request_get_target_uid(req);
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       if (appid == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       app_status = _app_status_find_by_appid(appid, uid);
+       pid = _app_status_is_running(app_status);
+       if (pid <= 0) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       status = _app_status_get_status(app_status);
+       if (status == STATUS_VISIBLE) {
+               if (_launch_get_focused_pid() == pid)
+                       status = STATUS_FOCUS;
+       }
+
+       _request_send_result(req, status);
+       _D("appid: %s, pid: %d, status: %d", appid, pid, status);
+
+       return 0;
+}
+
+static int __dispatch_app_get_last_caller_pid(request_h req)
+{
+       int pid;
+       int ret;
+       app_status_h app_status;
+       const char *pid_str;
+       bundle *b = _request_get_bundle(req);
+
+       if (b == NULL) {
+               _E("Failed to get bundle");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       pid_str = bundle_get_val(b, AUL_K_PID);
+       if (pid_str == NULL || !isdigit(pid_str[0])) {
+               _E("Failed to get pid");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       pid = atoi(pid_str);
+       app_status = _app_status_find(pid);
+       if (app_status == NULL) {
+               _E("Failed to get app status info(%d)", pid);
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = _app_status_get_last_caller_pid(app_status);
+       _D("app_get_last_caller_pid: %d : %d", pid, ret);
+       _request_send_result(req, ret);
+
+       return 0;
+}
+
+static int __dispatch_app_register_pid(request_h req)
+{
+       bundle *kb;
+       struct appinfo *ai;
+       const char *appid;
+       const char *component_type;
+       const char *pid_str;
+       int pid;
+       int ret;
+       uid_t target_uid = _request_get_target_uid(req);
+       int caller_pid = _request_get_pid(req);
+       app_status_h app_status;
+       int status = -1;
+       int focused = -1;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       if (appid == NULL)
+               return -1;
+
+       pid_str = bundle_get_val(kb, AUL_K_PID);
+       if (pid_str == NULL)
+               return -1;
+
+       pid = atoi(pid_str);
+       app_status = _app_status_find_by_appid(appid, target_uid);
+       ret = _app_status_is_running(app_status);
+       if (ret > 0) {
+               if (ret != pid)
+                       kill(pid, SIGKILL);
+               _D("status info is already exist: %s", appid);
+               return 0;
+       }
+       _D("appid: %s, pid: %d", appid, pid);
+
+       ai = _appinfo_find(target_uid, appid);
+       component_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+       _noti_send("app_status.app_register_pid", pid, 0, ai, kb);
+       _app_status_add_app_info(ai, pid, false, target_uid, caller_pid,
+                       false, NULL, false);
+       if (component_type && strcmp(component_type, APP_TYPE_SERVICE) != 0) {
+               ret = _signal_get_proc_status(pid, &status, &focused);
+               if (ret < 0)
+                       return -1;
+
+               if (focused == 1)
+                       _launch_set_focused_pid(pid);
+
+               if (status == PROC_STATUS_FG)
+                       status = STATUS_VISIBLE;
+               else if (status == PROC_STATUS_BG)
+                       status = STATUS_BG;
+               else
+                       return -1;
+
+               app_status = _app_status_find(pid);
+               if (app_status == NULL)
+                       return -1;
+
+               _app_status_update_status(app_status, status, false, true);
+       }
+
+       return 0;
+}
+
+static int __dispatch_app_running_instance_info(request_h req)
+{
+       int fd = _request_remove_fd(req);
+       int cmd = _request_get_cmd(req);
+       uid_t target_uid = _request_get_target_uid(req);
+
+       return _app_status_send_running_appinfo(fd, cmd, target_uid);
+}
+
+static int __dispatch_app_get_instance_id_by_pid(request_h req)
+{
+       int pid;
+       int ret;
+       const char *pid_str;
+       int fd = _request_remove_fd(req);
+       bundle *b = _request_get_bundle(req);
+
+       if (b == NULL) {
+               _E("Failed to get bundle");
+               aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR,
+                               NULL, 0, AUL_SOCK_NOREPLY);
+               return -1;
+       }
+
+       pid_str = bundle_get_val(b, AUL_K_PID);
+       if (pid_str == NULL || !isdigit(pid_str[0])) {
+               _E("Failed to get pid");
+               aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR,
+                               NULL, 0, AUL_SOCK_NOREPLY);
+               return -1;
+       }
+
+       pid = atoi(pid_str);
+       ret = _app_status_get_instance_id_bypid(fd, pid);
+       _D("app get instance-id by pid - pid(%d), ret(%d)", pid, ret);
+
+       return ret;
+}
+
+static request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = APP_RUNNING_INFO,
+               .callback = __dispatch_app_running_info
+       },
+       {
+               .cmd = APP_ALL_RUNNING_INFO,
+               .callback = __dispatch_app_all_running_info
+       },
+       {
+               .cmd = APP_IS_RUNNING,
+               .callback = __dispatch_app_is_running
+       },
+       {
+               .cmd = APP_GET_PID,
+               .callback = __dispatch_app_is_running
+       },
+       {
+               .cmd = APP_GET_APPID_BYPID,
+               .callback = __dispatch_app_get_appid_by_pid
+       },
+       {
+               .cmd = APP_GET_PKGID_BYPID,
+               .callback = __dispatch_app_get_pkgid_by_pid
+       },
+       {
+               .cmd = APP_STATUS_UPDATE,
+               .callback = __dispatch_app_status_update
+       },
+       {
+               .cmd = APP_GET_STATUS,
+               .callback = __dispatch_app_get_status
+       },
+       {
+               .cmd = APP_GET_STATUS_BY_APPID,
+               .callback = __dispatch_app_get_status_by_appid
+       },
+       {
+               .cmd = APP_GET_LAST_CALLER_PID,
+               .callback = __dispatch_app_get_last_caller_pid
+       },
+       {
+               .cmd = APP_REGISTER_PID,
+               .callback = __dispatch_app_register_pid
+       },
+       {
+               .cmd = APP_RUNNING_INSTANCE_INFO,
+               .callback = __dispatch_app_running_instance_info
+       },
+       {
+               .cmd = APP_GET_INSTANCE_ID_BYPID,
+               .callback = __dispatch_app_get_instance_id_by_pid
+       },
+
+};
+
+int _app_status_init(void)
+{
+       int ret;
+
+       __wd_table = g_hash_table_new(g_direct_hash, g_direct_equal);
+       if (__wd_table == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       ret = vconf_get_int(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS,
+                       &limit_bg_uiapps);
+       if (ret != VCONF_OK)
+               _E("Failed to get %s", VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS);
+
+       ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS,
+                       __vconf_cb, NULL);
+       if (ret != 0) {
+               _E("Failed to register callback for %s",
+                               VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS);
+       }
+
+       home_appid = vconf_get_str(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME);
+       ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME,
+                       __home_appid_vconf_cb, NULL);
+       if (ret != 0) {
+               _E("Failed to register callback for %s",
+                               VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME);
+       }
+
+       ret = _request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (ret < 0) {
+               _E("Failed to register cmds");
+               return -1;
+       }
+
+       return 0;
+}
+
+int _app_status_finish(void)
+{
+       int ret;
+       GSList *iter;
+       GSList *iter_next;
+       app_status_h app_status;
+
+       GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+               app_status = (app_status_h)iter->data;
+               _app_status_cleanup(app_status);
+       }
+
+       ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS,
+                       __vconf_cb);
+       if (ret != 0)
+               _E("Failed to remove a callback");
+
+       ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME,
+                       __home_appid_vconf_cb);
+       if (ret != 0)
+               _E("Failed to remove a callback");
+
+       free(home_appid);
+
+       if (__wd_table)
+               g_hash_table_destroy(__wd_table);
+
+       return 0;
+}
diff --git a/src/lib/amd_appinfo.c b/src/lib/amd_appinfo.c
new file mode 100644 (file)
index 0000000..261fc63
--- /dev/null
@@ -0,0 +1,2185 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <glib.h>
+#include <dirent.h>
+#include <package-manager.h>
+#include <pkgmgr-info.h>
+#include <vconf.h>
+#include <aul_sock.h>
+
+#include "amd_util.h"
+#include "amd_appinfo.h"
+#include "amd_launch.h"
+#include "amd_app_status.h"
+#include "amd_signal.h"
+#include "amd_app_property.h"
+#include "amd_suspend.h"
+#include "amd_login_monitor.h"
+
+#define CATEGORY_IME "http://tizen.org/category/ime"
+
+typedef int (*appinfo_handler_add_cb)(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data);
+typedef void (*appinfo_handler_remove_cb)(void *data);
+
+typedef struct _appinfo_vft {
+       appinfo_handler_add_cb constructor;
+       appinfo_handler_remove_cb destructor;
+} appinfo_vft;
+
+struct user_appinfo {
+       uid_t uid;
+       GHashTable *tbl; /* key is appid, value is struct appinfo */
+};
+
+struct app_event_info {
+       int req_id;
+       int type;
+       uid_t uid;
+};
+
+struct pkg_event_info {
+       uid_t target_uid;
+       const char *pkgid;
+};
+
+struct callback_info {
+       appinfo_iter_callback cb;
+       void *user_data;
+};
+
+static pkgmgr_client *pc;
+static GHashTable *user_tbl;
+static GHashTable *pkg_pending;
+static GList *app_event_list;
+static int gles = 1;
+
+static void __free_appinfo_splash_image(gpointer data)
+{
+       struct appinfo_splash_image *splash_image = data;
+
+       if (splash_image == NULL)
+               return;
+
+       if (splash_image->color_depth)
+               free(splash_image->color_depth);
+       if (splash_image->indicatordisplay)
+               free(splash_image->indicatordisplay);
+       if (splash_image->type)
+               free(splash_image->type);
+       if (splash_image->src)
+               free(splash_image->src);
+       free(splash_image);
+}
+
+static void __free_user_appinfo(gpointer data)
+{
+       struct user_appinfo *info = (struct user_appinfo *)data;
+
+       g_hash_table_destroy(info->tbl);
+       free(info);
+}
+
+static int __read_background_category(const char *category_name,
+               void *user_data)
+{
+       struct appinfo *c = user_data;
+       int category = (intptr_t)(c->val[AIT_BG_CATEGORY]);
+
+       if (!category_name)
+               return 0;
+
+       if (strcmp(category_name, "disable") == 0) {
+               c->val[AIT_BG_CATEGORY] = 0x00;
+               return -1;
+       }
+
+       if (strcmp(category_name, "media") == 0) {
+               c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+                               BACKGROUND_CATEGORY_MEDIA));
+       } else if (strcmp(category_name, "download") == 0) {
+               c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+                               BACKGROUND_CATEGORY_DOWNLOAD));
+       } else if (strcmp(category_name, "background-network") == 0) {
+               c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+                               BACKGROUND_CATEGORY_BACKGROUND_NETWORK));
+       } else if (strcmp(category_name, "location") == 0) {
+               c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+                               BACKGROUND_CATEGORY_LOCATION));
+       } else if (strcmp(category_name, "sensor") == 0) {
+               c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+                               BACKGROUND_CATEGORY_SENSOR));
+       } else if (strcmp(category_name, "iot-communication") == 0) {
+               c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+                               BACKGROUND_CATEGORY_IOT_COMMUNICATION));
+       } else if (strcmp(category_name, "system") == 0) {
+               c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+                               BACKGROUND_CATEGORY_SYSTEM));
+       }
+
+       return 0;
+}
+
+static void __appinfo_remove_splash_screen(void *data)
+{
+       struct appinfo_splash_screen *splash_screen =
+               (struct appinfo_splash_screen *)data;
+
+       if (splash_screen == NULL)
+               return;
+
+       if (splash_screen->portrait)
+               g_hash_table_destroy(splash_screen->portrait);
+       if (splash_screen->landscape)
+               g_hash_table_destroy(splash_screen->landscape);
+       free(splash_screen);
+}
+
+static int __appinfo_add_exec(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       char *exec = NULL;
+
+       ret = pkgmgrinfo_appinfo_get_exec(handle, &exec);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get exec");
+               return -1;
+       }
+
+       info->val[AIT_EXEC] = strdup(exec);
+       if (info->val[AIT_EXEC] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_pkgtype(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       char *pkgtype = NULL;
+
+       ret = pkgmgrinfo_appinfo_get_pkgtype(handle, &pkgtype);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get pkgtype");
+               return -1;
+       }
+
+       info->val[AIT_PKGTYPE] = strdup(pkgtype);
+       if (info->val[AIT_PKGTYPE] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_onboot(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool onboot = false;
+
+       ret = pkgmgrinfo_appinfo_is_onboot(handle, &onboot);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get onboot");
+               return -1;
+       }
+
+       info->val[AIT_ONBOOT] = strdup(onboot ? "true" : "false");
+       if (info->val[AIT_ONBOOT] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_restart(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool restart = false;
+
+       ret = pkgmgrinfo_appinfo_is_autorestart(handle, &restart);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get restart");
+               return -1;
+       }
+
+       info->val[AIT_RESTART] = GINT_TO_POINTER(restart ? 1 : 0);
+
+       return 0;
+}
+
+static int __appinfo_add_multi(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool multiple = false;
+
+       ret = pkgmgrinfo_appinfo_is_multiple(handle, &multiple);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get multiple");
+               return -1;
+       }
+
+       info->val[AIT_MULTI] = strdup(multiple ? "true" : "false");
+       if (info->val[AIT_MULTI] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_hwacc(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       pkgmgrinfo_app_hwacceleration hwacc;
+
+       ret = pkgmgrinfo_appinfo_get_hwacceleration(handle, &hwacc);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get hwacc");
+               return -1;
+       }
+
+       info->val[AIT_HWACC] = strdup(
+                               (gles == 0 ||
+                                hwacc == PMINFO_HWACCELERATION_OFF) ?
+                               "NOT_USE" :
+                               (hwacc == PMINFO_HWACCELERATION_ON) ?
+                               "USE" :
+                               "SYS");
+       if (info->val[AIT_HWACC] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_perm(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       pkgmgrinfo_permission_type permission;
+
+       ret = pkgmgrinfo_appinfo_get_permission_type(handle, &permission);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get permission type");
+               return -1;
+       }
+
+       info->val[AIT_PERM] = strdup(
+                               (permission == PMINFO_PERMISSION_SIGNATURE) ?
+                               "signature" :
+                               (permission == PMINFO_PERMISSION_PRIVILEGE) ?
+                               "privilege" :
+                               "normal");
+       if (info->val[AIT_PERM] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_pkgid(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       char *pkgid = NULL;
+
+       ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgid);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get pkgid");
+               return -1;
+       }
+
+       info->val[AIT_PKGID] = strdup(pkgid);
+       if (info->val[AIT_PKGID] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_preload(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool preload = false;
+
+       ret = pkgmgrinfo_appinfo_is_preload(handle, &preload);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get preload");
+               return -1;
+       }
+
+       info->val[AIT_PRELOAD] = strdup(preload ? "true" : "false");
+       if (info->val[AIT_PRELOAD] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_status(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       info->val[AIT_STATUS] = strdup("installed");
+       if (info->val[AIT_STATUS] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_pool(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool process_pool = false;
+
+       ret = pkgmgrinfo_appinfo_is_process_pool(handle, &process_pool);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get process_pool");
+               return -1;
+       }
+
+       info->val[AIT_POOL] = strdup(process_pool ? "true" : "false");
+       if (info->val[AIT_POOL] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_comptype(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       char *component_type = NULL;
+
+       ret = pkgmgrinfo_appinfo_get_component_type(handle, &component_type);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get component type");
+               return -1;
+       }
+
+       info->val[AIT_COMPTYPE] = strdup(component_type);
+       if (info->val[AIT_COMPTYPE] == NULL) {
+               _E("Ouf ot memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_tep(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       char *tep_name = NULL;
+
+       pkgmgrinfo_appinfo_get_tep_name(handle, &tep_name);
+       if (tep_name && strlen(tep_name) > 0) {
+               info->val[AIT_TEP] = strdup(tep_name);
+               if (info->val[AIT_TEP] == NULL) {
+                       _E("Out of memory");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_mountable_pkg(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       char *tpk_name = NULL;
+
+       pkgmgrinfo_appinfo_get_zip_mount_file(handle, &tpk_name);
+       if (tpk_name && strlen(tpk_name) > 0) {
+               info->val[AIT_MOUNTABLE_PKG] = strdup(tpk_name);
+               if (info->val[AIT_MOUNTABLE_PKG] == NULL) {
+                       _E("Out of memory");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_storage_type(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       pkgmgrinfo_installed_storage installed_storage;
+
+       ret = pkgmgrinfo_appinfo_get_installed_storage_location(handle,
+                       &installed_storage);
+       if (ret == PMINFO_R_OK) {
+               if (installed_storage == PMINFO_INTERNAL_STORAGE)
+                       info->val[AIT_STORAGE_TYPE] = strdup("internal");
+               else if (installed_storage == PMINFO_EXTERNAL_STORAGE)
+                       info->val[AIT_STORAGE_TYPE] = strdup("external");
+       } else {
+               info->val[AIT_STORAGE_TYPE] = strdup("internal");
+       }
+
+       if (info->val[AIT_STORAGE_TYPE] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_bg_category(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+
+       ret = pkgmgrinfo_appinfo_foreach_background_category(handle,
+                       __read_background_category, info);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get background category");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_launch_mode(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       char *mode = NULL;
+
+       ret = pkgmgrinfo_appinfo_get_launch_mode(handle, &mode);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get launch_mode");
+               return -1;
+       }
+
+       info->val[AIT_LAUNCH_MODE] = strdup(mode ? mode : "single");
+       if (info->val[AIT_LAUNCH_MODE] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_global(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool is_global = false;
+
+       ret = pkgmgrinfo_appinfo_is_global(handle, &is_global);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get is_global info");
+               return -1;
+       }
+
+       info->val[AIT_GLOBAL] = strdup(is_global ? "true" : "false");
+       if (info->val[AIT_GLOBAL] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_effective_appid(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       char *effective_appid = NULL;
+
+       pkgmgrinfo_appinfo_get_effective_appid(handle, &effective_appid);
+       if (effective_appid && strlen(effective_appid) > 0) {
+               info->val[AIT_EFFECTIVE_APPID] = strdup(effective_appid);
+               if (info->val[AIT_EFFECTIVE_APPID] == NULL) {
+                       _E("Out of memory");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_taskmanage(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       bool taskmanage = false;
+
+       pkgmgrinfo_appinfo_is_taskmanage(handle, &taskmanage);
+
+       info->val[AIT_TASKMANAGE] = strdup(taskmanage ? "true" : "false");
+       if (info->val[AIT_TASKMANAGE] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_apptype(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       char *apptype = NULL;
+
+       ret = pkgmgrinfo_appinfo_get_apptype(handle, &apptype);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get apptype");
+               return -1;
+       }
+
+       info->val[AIT_APPTYPE] = strdup(apptype);
+       if (info->val[AIT_APPTYPE] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_root_path(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       char *path = NULL;
+
+       ret = pkgmgrinfo_appinfo_get_root_path(handle, &path);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get root path");
+               return -1;
+       }
+
+       if (path) {
+               info->val[AIT_ROOT_PATH] = strdup(path);
+               if (info->val[AIT_ROOT_PATH] == NULL) {
+                       _E("Out of memory");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int __add_splash_screen_list_cb(const char *src, const char *type,
+               const char *orientation, const char *indicatordisplay,
+               const char *operation, const char *color_depth, void *user_data)
+{
+       struct appinfo *info = (struct appinfo *)user_data;
+       struct appinfo_splash_screen *splash_screen;
+       struct appinfo_splash_image *splash_image;
+       char *key;
+
+       splash_image = (struct appinfo_splash_image *)calloc(1,
+                       sizeof(struct appinfo_splash_image));
+       if (splash_image == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       splash_image->src = strdup(src);
+       if (splash_image->src == NULL) {
+               _E("Out of memory");
+               free(splash_image);
+               return -1;
+       }
+
+       splash_image->type = strdup(type);
+       if (splash_image->type == NULL) {
+               _E("Out of memory");
+               __free_appinfo_splash_image(splash_image);
+               return -1;
+       }
+
+       splash_image->indicatordisplay = strdup(indicatordisplay);
+       if (splash_image->indicatordisplay == NULL) {
+               _E("Out of memory");
+               __free_appinfo_splash_image(splash_image);
+               return -1;
+       }
+
+       splash_image->color_depth = strdup(color_depth);
+       if (splash_image->color_depth == NULL) {
+               _E("Out of memory");
+               __free_appinfo_splash_image(splash_image);
+               return -1;
+       }
+
+       key = strdup(operation);
+       if (key == NULL) {
+               _E("Out of memory");
+               __free_appinfo_splash_image(splash_image);
+               return -1;
+       }
+
+       splash_screen = (struct appinfo_splash_screen *)
+               info->val[AIT_SPLASH_SCREEN];
+       if (splash_screen == NULL) {
+               splash_screen = (struct appinfo_splash_screen *)calloc(1,
+                               sizeof(struct appinfo_splash_screen));
+               if (splash_screen == NULL) {
+                       _E("out of memory");
+                       __free_appinfo_splash_image(splash_image);
+                       free(key);
+                       return -1;
+               }
+               info->val[AIT_SPLASH_SCREEN] = (char *)splash_screen;
+       }
+
+       if (strcasecmp(orientation, "portrait") == 0) {
+               if (splash_screen->portrait == NULL) {
+                       splash_screen->portrait = g_hash_table_new_full(
+                                       g_str_hash, g_str_equal, free,
+                                       __free_appinfo_splash_image);
+               }
+               g_hash_table_insert(splash_screen->portrait, key, splash_image);
+       } else if (strcasecmp(orientation, "landscape") == 0) {
+               if (splash_screen->landscape == NULL) {
+                       splash_screen->landscape = g_hash_table_new_full(
+                                       g_str_hash, g_str_equal, free,
+                                       __free_appinfo_splash_image);
+               }
+               g_hash_table_insert(splash_screen->landscape, key,
+                               splash_image);
+       } else {
+               __free_appinfo_splash_image(splash_image);
+               free(key);
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_splash_screens(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+
+       ret = pkgmgrinfo_appinfo_foreach_splash_screen(handle,
+                       __add_splash_screen_list_cb, info);
+       if (ret < 0) {
+               _E("Failed to get splash screen");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_splash_screen_display(
+               const pkgmgrinfo_appinfo_h handle, struct appinfo *info,
+               void *data)
+{
+       bool splash_screen_display = true;
+       int ret;
+
+       ret = pkgmgrinfo_appinfo_get_splash_screen_display(handle,
+                       &splash_screen_display);
+       if (ret < 0)
+               _D("Failed to get splash screen display");
+
+       info->val[AIT_SPLASH_SCREEN_DISPLAY] =
+               GINT_TO_POINTER(splash_screen_display ? 1 : 0);
+
+       return 0;
+}
+
+static int __appinfo_add_api_version(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       char *api_version;
+
+       ret = pkgmgrinfo_appinfo_get_api_version(handle, &api_version);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get api version");
+               return -1;
+       }
+
+       info->val[AIT_API_VERSION] = strdup(api_version);
+       if (info->val[AIT_API_VERSION] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_enablement(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool disabled = false;
+
+       ret = pkgmgrinfo_appinfo_is_disabled(handle, &disabled);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get enablement");
+               return -1;
+       }
+
+       info->val[AIT_ENABLEMENT] = GINT_TO_POINTER(disabled ? 0 : 1);
+
+       return 0;
+}
+
+static int __appinfo_add_cooldown_mode(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       int support_mode = 0;
+
+       ret = pkgmgrinfo_appinfo_get_support_mode(handle, &support_mode);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get support mode value");
+               return -1;
+       }
+
+       if (support_mode & APP_SUPPORT_MODE_COOL_DOWN_VAL)
+               info->val[AIT_COOLDOWN] = strdup("true");
+       else
+               info->val[AIT_COOLDOWN] = strdup("false");
+       if (info->val[AIT_COOLDOWN] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_system(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool system = false;
+
+       ret = pkgmgrinfo_appinfo_is_system(handle, &system);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get support mode value");
+               return -1;
+       }
+
+       if (system)
+               info->val[AIT_SYSTEM] = strdup("true");
+       else
+               info->val[AIT_SYSTEM] = strdup("false");
+       if (info->val[AIT_SYSTEM] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __appinfo_add_ime(const pkgmgrinfo_appinfo_h handle,
+               struct appinfo *info, void *data)
+{
+       int ret;
+       bool exist = false;
+
+       ret = pkgmgrinfo_appinfo_is_category_exist(handle, CATEGORY_IME,
+                       &exist);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to check ime category");
+               return -1;
+       }
+
+       info->val[AIT_IME] = strdup(exist ? "true" : "false");
+       if (info->val[AIT_IME] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+static  appinfo_vft appinfo_table[AIT_MAX] = {
+       [AIT_NAME] = {
+               .constructor = NULL,
+               .destructor = NULL
+       },
+       [AIT_EXEC] = {
+               .constructor = __appinfo_add_exec,
+               .destructor = free
+       },
+       [AIT_PKGTYPE] = {
+               .constructor = __appinfo_add_pkgtype,
+               .destructor = free
+       },
+       [AIT_ONBOOT] = {
+               .constructor = __appinfo_add_onboot,
+               .destructor = free
+       },
+       [AIT_RESTART] = {
+               .constructor = __appinfo_add_restart,
+               .destructor = NULL
+       },
+       [AIT_MULTI] = {
+               .constructor = __appinfo_add_multi,
+               .destructor = free
+       },
+       [AIT_HWACC] = {
+               .constructor = __appinfo_add_hwacc,
+               .destructor = free
+       },
+       [AIT_PERM] = {
+               .constructor = __appinfo_add_perm,
+               .destructor = free
+       },
+       [AIT_PKGID] = {
+               .constructor = __appinfo_add_pkgid,
+               .destructor = free
+       },
+       [AIT_PRELOAD] = {
+               .constructor = __appinfo_add_preload,
+               .destructor = free
+       },
+       [AIT_STATUS] = {
+               .constructor = __appinfo_add_status,
+               .destructor = free
+       },
+       [AIT_POOL] = {
+               .constructor = __appinfo_add_pool,
+               .destructor = free
+       },
+       [AIT_COMPTYPE] = {
+               .constructor = __appinfo_add_comptype,
+               .destructor = free
+       },
+       [AIT_TEP] = {
+               .constructor = __appinfo_add_tep,
+               .destructor = free
+       },
+       [AIT_MOUNTABLE_PKG] = {
+               .constructor = __appinfo_add_mountable_pkg,
+               .destructor = free
+       },
+       [AIT_STORAGE_TYPE] = {
+               .constructor = __appinfo_add_storage_type,
+               .destructor = free
+       },
+       [AIT_BG_CATEGORY] = {
+               .constructor = __appinfo_add_bg_category,
+               .destructor = NULL
+       },
+       [AIT_LAUNCH_MODE] = {
+               .constructor = __appinfo_add_launch_mode,
+               .destructor = free
+       },
+       [AIT_GLOBAL] = {
+               .constructor = __appinfo_add_global,
+               .destructor = free
+       },
+       [AIT_EFFECTIVE_APPID] = {
+               .constructor = __appinfo_add_effective_appid,
+               .destructor = free
+       },
+       [AIT_TASKMANAGE] = {
+               .constructor = __appinfo_add_taskmanage,
+               .destructor = free
+       },
+       [AIT_VISIBILITY] = {
+               .constructor = NULL,
+               .destructor = free
+       },
+       [AIT_APPTYPE] = {
+               .constructor = __appinfo_add_apptype,
+               .destructor = free
+       },
+       [AIT_ROOT_PATH] = {
+               .constructor = __appinfo_add_root_path,
+               .destructor = free
+       },
+       [AIT_SPLASH_SCREEN] = {
+               .constructor = __appinfo_add_splash_screens,
+               .destructor = __appinfo_remove_splash_screen
+       },
+       [AIT_SPLASH_SCREEN_DISPLAY] = {
+               .constructor = __appinfo_add_splash_screen_display,
+               .destructor = NULL
+       },
+       [AIT_API_VERSION] = {
+               .constructor = __appinfo_add_api_version,
+               .destructor = free
+       },
+       [AIT_ENABLEMENT] = {
+               .constructor = __appinfo_add_enablement,
+               .destructor = NULL
+       },
+       [AIT_COOLDOWN] = {
+               .constructor = __appinfo_add_cooldown_mode,
+               .destructor = free
+       },
+       [AIT_SYSTEM] = {
+               .constructor = __appinfo_add_system,
+               .destructor = free
+       },
+       [AIT_IME] = {
+               .constructor = __appinfo_add_ime,
+               .destructor = free
+       },
+};
+
+static void __appinfo_remove_handler(gpointer data)
+{
+       struct appinfo *c = data;
+       int i;
+
+       if (!c)
+               return;
+
+       for (i = AIT_START; i < AIT_MAX; i++) {
+               if (appinfo_table[i].destructor && c->val[i] != NULL)
+                       appinfo_table[i].destructor(c->val[i]);
+       }
+
+       free(c);
+}
+
+static int __appinfo_insert_handler (const pkgmgrinfo_appinfo_h handle,
+                                       void *data)
+{
+       int i;
+       struct appinfo *c;
+       struct user_appinfo *info = (struct user_appinfo *)data;
+       char *appid;
+       int ret;
+       char err_buf[1024];
+
+       if (!handle || !info) {
+               _E("null app handle");
+               return -1;
+       }
+
+       if (pkgmgrinfo_appinfo_get_appid(handle, &appid) != PMINFO_R_OK) {
+               _E("fail to get appinfo");
+               return -1;
+       }
+
+       g_hash_table_remove(info->tbl, appid);
+
+       c = calloc(1, sizeof(struct appinfo));
+       if (!c) {
+               _E("create appinfo: %s",
+                               strerror_r(errno, err_buf, sizeof(err_buf)));
+               return -1;
+       }
+
+       c->val[AIT_NAME] = strdup(appid);
+       if (c->val[AIT_NAME] == NULL) {
+               _E("Out of memory");
+               free(c);
+               return -1;
+       }
+
+       for (i = AIT_START; i < AIT_MAX; i++) {
+               if (appinfo_table[i].constructor) {
+                       ret = appinfo_table[i].constructor(handle, c, info);
+                       if (ret < 0) {
+                               __appinfo_remove_handler(c);
+                               return -1;
+                       }
+               }
+       }
+
+       SECURE_LOGD("%s : %s : %s : %s", c->val[AIT_NAME], c->val[AIT_COMPTYPE],
+               c->val[AIT_PKGTYPE], c->val[AIT_APPTYPE]);
+
+       g_hash_table_insert(info->tbl, c->val[AIT_NAME], c);
+       _app_property_insert(info->uid, c->val[AIT_NAME]);
+
+       return 0;
+}
+
+static int __appinfo_update_handler(const pkgmgrinfo_appinfo_h handle,
+               void *data)
+{
+       int i;
+       struct appinfo *c;
+       struct user_appinfo *info = (struct user_appinfo *)data;
+       char *appid;
+       int ret;
+       bool restart;
+       int auto_restart;
+
+       if (!handle || !info) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       ret = pkgmgrinfo_appinfo_get_appid(handle, &appid);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get appinfo");
+               return -1;
+       }
+
+       c = (struct appinfo *)g_hash_table_lookup(info->tbl, appid);
+       if (!c) {
+               c = calloc(1, sizeof(struct appinfo));
+               if (!c) {
+                       _E("Failed to create appinfo(%s)", appid);
+                       return -1;
+               }
+
+               c->val[AIT_NAME] = strdup(appid);
+               if (c->val[AIT_NAME] == NULL) {
+                       _E("Out of memory");
+                       free(c);
+                       return -1;
+               }
+
+               g_hash_table_insert(info->tbl, c->val[AIT_NAME], c);
+       }
+
+       if (c->val[AIT_STATUS] && strcmp(c->val[AIT_STATUS], "restart") == 0)
+               restart = true;
+       else
+               restart = false;
+
+       _app_property_delete(info->uid, appid);
+       for (i = AIT_START + 1; i < AIT_MAX; i++) {
+               if (appinfo_table[i].destructor && c->val[i])
+                       appinfo_table[i].destructor(c->val[i]);
+               c->val[i] = NULL;
+
+               if (appinfo_table[i].constructor) {
+                       ret = appinfo_table[i].constructor(handle, c, info);
+                       if (ret < 0) {
+                               g_hash_table_remove(info->tbl, appid);
+                               return -1;
+                       }
+               }
+       }
+       SECURE_LOGD("%s : %s : %s : %s",
+                       c->val[AIT_NAME], c->val[AIT_COMPTYPE],
+                       c->val[AIT_PKGTYPE], c->val[AIT_APPTYPE]);
+       _app_property_insert(info->uid, c->val[AIT_NAME]);
+
+       auto_restart = GPOINTER_TO_INT(c->val[AIT_RESTART]);
+       if (auto_restart && restart)
+               _launch_start_app_local(info->uid, c->val[AIT_NAME]);
+
+       return 0;
+}
+
+static int __insert_appinfo(const pkgmgrinfo_appinfo_h handle, void *data)
+{
+       int ret;
+       struct appinfo *ai;
+       struct user_appinfo *info = (struct user_appinfo *)data;
+       char *appid = NULL;
+
+       ret = __appinfo_insert_handler(handle, data);
+       if (ret < 0)
+               return -1;
+
+       ret = pkgmgrinfo_appinfo_get_appid(handle, &appid);
+       if (ret != PMINFO_R_OK)
+               return -1;
+
+       ai = (struct appinfo *)g_hash_table_lookup(info->tbl, appid);
+       if (ai == NULL)
+               return -1;
+
+       _launch_start_onboot_app_local(info->uid, appid, ai);
+
+       return 0;
+}
+
+static void __remove_user_appinfo(uid_t uid)
+{
+       g_hash_table_remove(user_tbl, GINT_TO_POINTER(uid));
+}
+
+static struct user_appinfo *__add_user_appinfo(uid_t uid)
+{
+       int r;
+       struct user_appinfo *info;
+
+       info = calloc(1, sizeof(struct user_appinfo));
+       if (info == NULL) {
+               _E("out of memory");
+               return NULL;
+       }
+
+       info->uid = uid;
+       info->tbl = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+                       __appinfo_remove_handler);
+       if (info->tbl == NULL) {
+               _E("out of memory");
+               free(info);
+               return NULL;
+       }
+
+       g_hash_table_insert(user_tbl, GINT_TO_POINTER(uid), info);
+
+       r = pkgmgrinfo_appinfo_get_usr_installed_list_full(
+                       __appinfo_insert_handler, uid,
+                       PMINFO_APPINFO_GET_SPLASH_SCREEN, info);
+       if (r != PMINFO_R_OK) {
+               __remove_user_appinfo(uid);
+               return NULL;
+       }
+
+       _D("loaded appinfo table for uid %d", uid);
+
+       return info;
+}
+
+static struct user_appinfo *__find_user_appinfo(uid_t uid)
+{
+       return g_hash_table_lookup(user_tbl, GINT_TO_POINTER(uid));
+}
+
+static void __appinfo_set_blocking_cb(void *user_data,
+               const char *appid, struct appinfo *info)
+{
+       struct pkg_event_info *pkg_info = (struct pkg_event_info *)user_data;
+
+       if (strcmp(info->val[AIT_PKGID], pkg_info->pkgid))
+               return;
+
+       if (pkg_info->target_uid == GLOBAL_USER &&
+                       !strcmp(info->val[AIT_GLOBAL], "false"))
+               return;
+       else if (pkg_info->target_uid != GLOBAL_USER &&
+                       !strcmp(info->val[AIT_GLOBAL], "true"))
+               return;
+
+       free(info->val[AIT_STATUS]);
+       info->val[AIT_STATUS] = strdup("blocking");
+       _D("%s status changed: blocking", appid);
+}
+
+static void __appinfo_unset_blocking_cb(void *user_data,
+               const char *appid, struct appinfo *info)
+{
+       struct pkg_event_info *pkg_info = (struct pkg_event_info *)user_data;
+
+       if (strcmp(info->val[AIT_PKGID], pkg_info->pkgid))
+               return;
+
+       if (pkg_info->target_uid == GLOBAL_USER &&
+                       !strcmp(info->val[AIT_GLOBAL], "false"))
+               return;
+       else if (pkg_info->target_uid != GLOBAL_USER &&
+                       !strcmp(info->val[AIT_GLOBAL], "true"))
+               return;
+
+       free(info->val[AIT_STATUS]);
+       info->val[AIT_STATUS] = strdup("installed");
+       if (info->val[AIT_STATUS] == NULL)
+               _W("Out of memory");
+       _D("%s status changed: installed", appid);
+}
+
+static gboolean __appinfo_remove_cb(gpointer key, gpointer value, gpointer data)
+{
+       struct pkg_event_info *pkg_info = (struct pkg_event_info *)data;
+       struct appinfo *info = (struct appinfo *)value;
+
+       if (strcmp(info->val[AIT_PKGID], pkg_info->pkgid))
+               return FALSE;
+
+       if (pkg_info->target_uid == GLOBAL_USER &&
+                       !strcmp(info->val[AIT_GLOBAL], "false"))
+               return FALSE;
+       else if (pkg_info->target_uid != GLOBAL_USER &&
+                       !strcmp(info->val[AIT_GLOBAL], "true"))
+               return FALSE;
+
+       _app_property_delete(GPOINTER_TO_UINT(key), info->val[AIT_NAME]);
+
+       _D("appinfo removed: %s", info->val[AIT_NAME]);
+       return TRUE;
+}
+
+static void __appinfo_delete_on_event(uid_t uid, void *data)
+{
+       struct user_appinfo *info;
+       app_property_h prop;
+
+       info = __find_user_appinfo(uid);
+       if (info == NULL) {
+               _E("cannot find appinfo for uid %d", uid);
+               return;
+       }
+
+       prop = _app_property_find(uid);
+       _app_property_cache_invalidate(prop);
+       g_hash_table_foreach_remove(info->tbl, __appinfo_remove_cb,
+                       (gpointer)data);
+}
+
+static void __appinfo_insert_on_event(uid_t uid, const char *pkgid)
+{
+       app_property_h prop;
+
+       prop = _app_property_find(uid);
+       _app_property_cache_invalidate(prop);
+       _appinfo_insert(uid, pkgid);
+}
+
+static void __appinfo_update_on_event(uid_t uid, void *data)
+{
+       struct pkg_event_info *pkg_info = (struct pkg_event_info *)data;
+       struct user_appinfo *info;
+       app_property_h prop;
+       pkgmgrinfo_pkginfo_h handle;
+       int ret;
+
+       info = __find_user_appinfo(uid);
+       if (info == NULL) {
+               _E("cannot find appinfo for uid %d", uid);
+               return;
+       }
+
+       prop = _app_property_find(uid);
+       _app_property_cache_invalidate(prop);
+
+       ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkg_info->pkgid, uid, &handle);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to get pkginfo(%s)", pkg_info->pkgid);
+               return;
+       }
+
+       ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP,
+                       __appinfo_update_handler, info, info->uid);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to update pkginfo(%s)", pkg_info->pkgid);
+               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+               return;
+       }
+
+       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+}
+
+static void __set_blocking(struct pkg_event_info *info)
+{
+       uid_t *uids = NULL;
+       int r;
+       int i;
+
+       if (info->target_uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return;
+
+               for (i = 0; i < r; i++) {
+                       _appinfo_foreach(uids[i],
+                                       __appinfo_set_blocking_cb, info);
+                       _D("terminate apps by PackageID - %s", info->pkgid);
+                       _app_status_terminate_apps_by_pkgid(info->pkgid,
+                                       uids[i]);
+               }
+               free(uids);
+
+               return;
+       }
+
+       _appinfo_foreach(info->target_uid, __appinfo_set_blocking_cb, info);
+       _D("terminate apps by PackageID - %s", info->pkgid);
+       _app_status_terminate_apps_by_pkgid(info->pkgid, info->target_uid);
+}
+
+static void __unset_blocking(struct pkg_event_info *info)
+{
+       uid_t *uids = NULL;
+       int r;
+       int i;
+
+       if (info->target_uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return;
+
+               for (i = 0; i < r; i++) {
+                       _appinfo_foreach(uids[i],
+                                       __appinfo_unset_blocking_cb, info);
+               }
+               free(uids);
+
+               return;
+       }
+
+       _appinfo_foreach(info->target_uid, __appinfo_unset_blocking_cb, info);
+}
+
+static void __delete_on_event(struct pkg_event_info *info)
+{
+       uid_t *uids = NULL;
+       int r;
+       int i;
+
+       if (info->target_uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return;
+
+               for (i = 0; i < r; i++)
+                       __appinfo_delete_on_event(uids[i], info);
+               free(uids);
+
+               return;
+       }
+
+       __appinfo_delete_on_event(info->target_uid, info);
+}
+
+static void __insert_on_event(struct pkg_event_info *info)
+{
+       uid_t *uids = NULL;
+       int r;
+       int i;
+
+       if (info->target_uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return;
+
+               for (i = 0; i < r; i++)
+                       __appinfo_insert_on_event(uids[i], info->pkgid);
+               free(uids);
+
+               return;
+       }
+
+       __appinfo_insert_on_event(info->target_uid, info->pkgid);
+}
+
+static void __update_on_event(struct pkg_event_info *info)
+{
+       uid_t *uids = NULL;
+       int r;
+       int i;
+
+       if (info->target_uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return;
+
+               for (i = 0; i < r; i++)
+                       __appinfo_update_on_event(uids[i], info);
+               free(uids);
+
+               return;
+       }
+
+       __appinfo_update_on_event(info->target_uid, info);
+}
+
+static int __appinfo_is_pkg_exist(uid_t uid, const char *pkgid)
+{
+       int r;
+       struct user_appinfo *info;
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       uid_t *uids = NULL;
+       struct appinfo *ai;
+
+       if (pkgid == NULL)
+               return 0;
+
+       if (uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return 0;
+
+               uid = uids[0];
+
+               free(uids);
+       }
+
+       info = __find_user_appinfo(uid);
+       if (info == NULL) {
+               _E("cannot find appinfo for uid %d", uid);
+               return 0;
+       }
+
+       g_hash_table_iter_init(&iter, info->tbl);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               ai = (struct appinfo *)value;
+               if (strcmp(pkgid, ai->val[AIT_PKGID]) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static void __appinfo_enable_pkg_apps(uid_t uid, const char *pkgid, int enable)
+{
+       int r;
+       int i;
+       struct user_appinfo *info;
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       uid_t *uids = NULL;
+       struct appinfo *ai;
+       int prev_val;
+       const char *appid;
+
+       if (pkgid == NULL)
+               return;
+
+       if (uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return;
+
+               for (i = 0; i < r; i++)
+                       __appinfo_enable_pkg_apps(uids[i], pkgid, enable);
+
+               free(uids);
+
+               return;
+       }
+
+       info = __find_user_appinfo(uid);
+       if (info == NULL) {
+               _E("cannot find appinfo for uid %d", uid);
+               return;
+       }
+
+       g_hash_table_iter_init(&iter, info->tbl);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               ai = (struct appinfo *)value;
+               if (strcmp(pkgid, ai->val[AIT_PKGID]) == 0) {
+                       _appinfo_get_int_value(ai, AIT_ENABLEMENT, &prev_val);
+                       _appinfo_set_int_value(ai, AIT_ENABLEMENT, enable);
+                       if (prev_val == 0 && enable == 1) {
+                               appid = _appinfo_get_value(ai, AIT_NAME);
+                               _launch_start_onboot_app_local(uid, appid, ai);
+                       }
+               }
+       }
+}
+
+static void __update_property(uid_t uid)
+{
+       uid_t *uids = NULL;
+       int r;
+       int i;
+
+       if (uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return;
+
+               for (i = 0; i < r; i++) {
+                       _app_property_unload(uids[i]);
+                       _app_property_load(uids[i]);
+               }
+
+               free(uids);
+
+               return;
+       }
+
+       _app_property_unload(uid);
+       _app_property_load(uid);
+}
+
+static int __package_event_cb(uid_t target_uid, int req_id,
+               const char *pkg_type, const char *pkgid,
+               const char *key, const char *val, const void *pmsg, void *data)
+{
+       int ret;
+       char *op;
+       struct pkg_event_info info = {
+               .target_uid = target_uid,
+               .pkgid = pkgid
+       };
+       pkgmgrinfo_pkginfo_h pkginfo;
+
+       if (!strcasecmp(key, "start")) {
+               if (!strcasecmp(val, "uninstall") ||
+                               !strcasecmp(val, "update") ||
+                               !strcasecmp(val, "move"))
+                       __set_blocking(&info);
+
+               g_hash_table_insert(pkg_pending, strdup(pkgid), strdup(val));
+       }
+
+       if (!strcasecmp(key, "error")) {
+               op = g_hash_table_lookup(pkg_pending, pkgid);
+               if (op == NULL)
+                       return 0;
+
+               if (!strcasecmp(op, "uninstall") ||
+                               !strcasecmp(op, "update") ||
+                               !strcasecmp(op, "move"))
+                       __unset_blocking(&info);
+
+               g_hash_table_remove(pkg_pending, pkgid);
+       }
+
+       if (!strcasecmp(key, "end")) {
+               op = g_hash_table_lookup(pkg_pending, pkgid);
+               if (op == NULL)
+                       return 0;
+
+               if (!strcasecmp(op, "uninstall")) {
+                       ret = pkgmgrinfo_pkginfo_get_usr_disabled_pkginfo(
+                                       info.pkgid, info.target_uid,
+                                       &pkginfo);
+                       if (ret == PMINFO_R_OK) {
+                               pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
+                               __unset_blocking(&info);
+                               __appinfo_enable_pkg_apps(info.target_uid,
+                                               info.pkgid, 0);
+                       } else {
+                               __delete_on_event(&info);
+                       }
+                       __update_property(info.target_uid);
+               } else if (!strcasecmp(op, "install")) {
+                       if (!__appinfo_is_pkg_exist(
+                                       info.target_uid,
+                                       info.pkgid)) {
+                               __insert_on_event(&info);
+                       } else {
+                               __unset_blocking(&info);
+                               __appinfo_enable_pkg_apps(info.target_uid,
+                                               info.pkgid, 1);
+                       }
+                       __update_property(info.target_uid);
+               } else if (!strcasecmp(op, "update") ||
+                               !strcasecmp(op, "move")) {
+                       __update_on_event(&info);
+                       __update_property(info.target_uid);
+               }
+
+               g_hash_table_remove(pkg_pending, pkgid);
+       }
+
+       return 0;
+}
+
+static void __add_app_event_info(int req_id, int type, uid_t uid)
+{
+       struct app_event_info *info;
+
+       info = (struct app_event_info *)malloc(sizeof(struct app_event_info));
+       if (info == NULL) {
+               _E("Out of memory");
+               return;
+       }
+
+       info->req_id = req_id;
+       info->type = type;
+       info->uid = uid;
+
+       app_event_list = g_list_append(app_event_list, (gpointer)info);
+}
+
+static struct app_event_info *__find_app_event_info(int req_id, uid_t uid)
+{
+       GList *iter;
+       struct app_event_info *info;
+
+       iter = g_list_first(app_event_list);
+       while (iter) {
+               info = (struct app_event_info *)iter->data;
+               if (info && info->req_id == req_id && info->uid == uid)
+                       return info;
+
+               iter = g_list_next(iter);
+       }
+
+       return NULL;
+}
+
+static void __remove_app_event_info(struct app_event_info *info)
+{
+       if (info == NULL)
+               return;
+
+       app_event_list = g_list_remove(app_event_list, info);
+       free(info);
+}
+
+static void __handle_app_event_start(const char *event_name,
+               struct appinfo *ai, const char *appid, int req_id, uid_t uid)
+{
+       int old = 0;
+
+       if (!strcasecmp(event_name, "enable_global_app_for_uid") ||
+                       !strcasecmp(event_name, "enable_app")) {
+               if (ai) {
+                       _appinfo_get_int_value(ai, AIT_ENABLEMENT, &old);
+                       old |= APP_ENABLEMENT_MASK_REQUEST;
+                       _appinfo_set_int_value(ai, AIT_ENABLEMENT, old);
+               }
+               __add_app_event_info(req_id, AIT_ENABLEMENT, uid);
+       } else if (!strcasecmp(event_name, "disable_global_app_for_uid") ||
+                       !strcasecmp(event_name, "disable_app")) {
+               __add_app_event_info(req_id, AIT_ENABLEMENT, uid);
+       } else if (!strcasecmp(event_name, "enable_app_splash_screen")) {
+               if (ai) {
+                       _appinfo_get_int_value(ai, AIT_SPLASH_SCREEN_DISPLAY,
+                                       &old);
+                       old |= APP_ENABLEMENT_MASK_REQUEST;
+                       _appinfo_set_int_value(ai, AIT_SPLASH_SCREEN_DISPLAY,
+                                       old);
+               }
+               __add_app_event_info(req_id, AIT_SPLASH_SCREEN_DISPLAY, uid);
+       } else if (!strcasecmp(event_name, "disable_app_splash_screen")) {
+               __add_app_event_info(req_id, AIT_SPLASH_SCREEN_DISPLAY, uid);
+       }
+}
+
+static void __handle_app_event_end(const char *event_name,
+               struct appinfo *ai, const char *appid, int req_id, uid_t uid)
+{
+       pkgmgrinfo_appinfo_h handle;
+       struct user_appinfo *info;
+       struct app_event_info *ei;
+       int old = 0;
+       int r;
+
+       ei = __find_app_event_info(req_id, uid);
+       if (ei == NULL)
+               return;
+
+       if (!strcasecmp(event_name, "ok")) {
+               if (ei->type == AIT_ENABLEMENT) {
+                       if (ai) {
+                               _appinfo_get_int_value(ai, ei->type, &old);
+                               old >>= 1;
+                               _appinfo_set_int_value(ai, ei->type, old);
+                       } else {
+                               info = __find_user_appinfo(uid);
+                               if (info == NULL) {
+                                       _E("Failed to load appinfo(%d)", uid);
+                                       __remove_app_event_info(ei);
+                                       return;
+                               }
+
+                               r = pkgmgrinfo_appinfo_get_usr_appinfo(appid,
+                                               uid, &handle);
+                               if (r != PMINFO_R_OK) {
+                                       _E("Failed to get appinfo(%s)", appid);
+                                       __remove_app_event_info(ei);
+                                       return;
+                               }
+
+                               _I("add the new appinfo(%s)", appid);
+                               __insert_appinfo(handle, info);
+                               pkgmgrinfo_appinfo_destroy_appinfo(handle);
+                               __remove_app_event_info(ei);
+                               return;
+                       }
+
+                       if (!(old & APP_ENABLEMENT_MASK_ACTIVE)) {
+                               _E("terminate apps: %s(%d)", appid, uid);
+                               _app_status_terminate_apps(appid, uid);
+                       } else if (old & APP_ENABLEMENT_MASK_ACTIVE) {
+                               _launch_start_onboot_app_local(uid, appid, ai);
+                       }
+               } else if (ei->type == AIT_SPLASH_SCREEN_DISPLAY) {
+                       if (ai) {
+                               _appinfo_get_int_value(ai, ei->type, &old);
+                               old >>= 1;
+                               _appinfo_set_int_value(ai, ei->type, old);
+                       }
+               }
+       } else if (!strcasecmp(event_name, "fail")) {
+               if (ei->type == AIT_ENABLEMENT ||
+                               ei->type == AIT_SPLASH_SCREEN_DISPLAY) {
+                       if (ai) {
+                               _appinfo_get_int_value(ai, ei->type, &old);
+                               old &= APP_ENABLEMENT_MASK_ACTIVE;
+                               _appinfo_set_int_value(ai, ei->type, old);
+                       }
+               }
+       }
+       __remove_app_event_info(ei);
+}
+
+static int __package_app_event_cb(uid_t target_uid, int req_id,
+               const char *pkg_type, const char *pkgid, const char *appid,
+               const char *key, const char *val, const void *pmsg, void *data)
+{
+       struct appinfo *ai;
+       uid_t *uids = NULL;
+       int r;
+       int i;
+
+       _D("appid:%s, key:%s, val:%s, req_id: %d, target_uid: %d",
+                       appid, key, val, req_id, target_uid);
+       if (target_uid < REGULAR_UID_MIN) {
+               r = _login_monitor_get_uids(&uids);
+               if (r <= 0)
+                       return 0;
+       } else {
+               r = 1;
+       }
+
+       for (i = 0; i < r; i++) {
+               if (uids)
+                       target_uid = uids[i];
+               ai = _appinfo_find(target_uid, appid);
+
+               if (!strcasecmp(key, "start")) {
+                       __handle_app_event_start(val, ai, appid, req_id,
+                                       target_uid);
+               } else if (!strcasecmp(key, "end")) {
+                       __handle_app_event_end(val, ai, appid, req_id,
+                                       target_uid);
+               }
+       }
+
+       free(uids);
+       return 0;
+}
+
+static int __init_package_event_handler(void *data)
+{
+       int ret;
+
+       pc = pkgmgr_client_new(PC_LISTENING);
+       if (pc == NULL)
+               return -1;
+
+       pkgmgr_client_set_status_type(pc, PKGMGR_CLIENT_STATUS_ALL);
+
+       ret = pkgmgr_client_listen_status(pc, __package_event_cb, NULL);
+       if (ret < 0)
+               return -1;
+
+       ret = pkgmgr_client_listen_app_status(pc, __package_app_event_cb, NULL);
+       if (ret < 0)
+               return -1;
+
+       return 0;
+}
+
+static void __fini_package_event_handler(void)
+{
+       pkgmgr_client_free(pc);
+}
+
+static void __reload_appinfo(gpointer key, gpointer value, gpointer user_data)
+{
+       int r;
+       struct user_appinfo *info = (struct user_appinfo *)value;
+
+       g_hash_table_remove_all(info->tbl);
+
+       r = pkgmgrinfo_appinfo_get_usr_installed_list_full(
+                       __appinfo_insert_handler, info->uid,
+                       PMINFO_APPINFO_GET_SPLASH_SCREEN, info);
+       if (r != PMINFO_R_OK) {
+               __remove_user_appinfo(info->uid);
+               return;
+       }
+
+       _D("reloaded appinfo table for uid %d", info->uid);
+}
+
+static int __dispatch_amd_reload_appinfo(request_h req)
+{
+       _D("AMD_RELOAD_APPINFO");
+       g_hash_table_foreach(user_tbl, __reload_appinfo, NULL);
+       _request_send_result(req, 0);
+
+       return 0;
+}
+
+static request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = AMD_RELOAD_APPINFO,
+               .callback = __dispatch_amd_reload_appinfo
+       },
+};
+
+int _appinfo_init(void)
+{
+       FILE *fp;
+       char buf[LINE_MAX];
+       char *tmp;
+       int r;
+
+       fp = fopen("/proc/cmdline", "r");
+       if (fp == NULL) {
+               _E("appinfo init failed: %d", errno);
+               return -1;
+       }
+
+       if (fgets(buf, sizeof(buf), fp) != NULL) {
+               tmp = strstr(buf, "gles");
+               if (tmp != NULL) {
+                       if (sscanf(tmp, "gles=%d", &gles) != 1)
+                               _D("Failed to convert format");
+               }
+       }
+       fclose(fp);
+
+       user_tbl = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+                       __free_user_appinfo);
+       if (user_tbl == NULL)
+               return -1;
+
+       pkg_pending = g_hash_table_new_full(g_str_hash, g_str_equal,
+                       free, free);
+       if (pkg_pending == NULL)
+               return -1;
+
+       if (__init_package_event_handler(NULL) < 0)
+               _signal_add_initializer(__init_package_event_handler, NULL);
+
+       r = _request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               _E("Failed to register cmds");
+               return -1;
+       }
+
+       return 0;
+}
+
+void _appinfo_fini(void)
+{
+       __fini_package_event_handler();
+       g_hash_table_destroy(user_tbl);
+       g_hash_table_destroy(pkg_pending);
+}
+
+struct appinfo *_appinfo_find(uid_t caller_uid, const char *appid)
+{
+       struct user_appinfo *info;
+
+       if (appid == NULL) {
+               _W("appid is NULL");
+               return NULL;
+       }
+
+       /* search from user table */
+       info = __find_user_appinfo(caller_uid);
+       if (info == NULL)
+               return NULL;
+
+       return g_hash_table_lookup(info->tbl, appid);
+}
+
+int _appinfo_insert(uid_t uid, const char *pkgid)
+{
+       int ret;
+       struct user_appinfo *info;
+       pkgmgrinfo_pkginfo_h handle;
+
+       info = __find_user_appinfo(uid);
+       if (info == NULL) {
+               _E("load appinfo for uid %d failed", uid);
+               return -1;
+       }
+
+       ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, uid, &handle);
+       if (ret != PMINFO_R_OK) {
+               _E("get pkginfo failed: %s", pkgid);
+               return -1;
+       }
+
+       ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP,
+                       __insert_appinfo, info, info->uid);
+       if (ret != PMINFO_R_OK) {
+               _E("add appinfo of pkg %s failed", pkgid);
+               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+               return -1;
+       }
+
+       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+
+       return 0;
+}
+
+const char *_appinfo_get_value(const struct appinfo *c, enum appinfo_type type)
+{
+       if (!c) {
+               _E("Invalid parameter");
+               return NULL;
+       }
+
+       if (type < AIT_START || type >= AIT_MAX)
+               return NULL;
+
+       return c->val[type];
+}
+
+const void *_appinfo_get_ptr_value(const struct appinfo *c,
+               enum appinfo_type type)
+{
+       if (!c) {
+               _E("Invalid parameter");
+               return NULL;
+       }
+
+       if (type < AIT_START || type >= AIT_MAX)
+               return NULL;
+
+       return c->val[type];
+}
+
+int _appinfo_get_int_value(const struct appinfo *c, enum appinfo_type type,
+               int *val)
+{
+       if (!c) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (type < AIT_START || type >= AIT_MAX)
+               return -1;
+
+       *val = GPOINTER_TO_INT(c->val[type]);
+
+       return 0;
+}
+
+int _appinfo_get_boolean(const struct appinfo *c, enum appinfo_type type,
+                       bool *val)
+{
+       if (!c || type < AIT_START || type >= AIT_MAX || c->val[type] == NULL) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (!strcmp(c->val[type], "true") || !strcmp(c->val[type], "1")) {
+               *val = true;
+       } else if (!strcmp(c->val[type], "false") ||
+               !strcmp(c->val[type], "0")) {
+               *val = false;
+       } else {
+               _E("Unexpected appinfo field value");
+               return -1;
+       }
+
+       return 0;
+}
+
+int _appinfo_set_value(struct appinfo *c, enum appinfo_type type,
+               const char *val)
+{
+       if (!c || !val) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (type < AIT_START || type >= AIT_MAX)
+               return -1;
+
+       _D("%s : %s : %s", c->val[AIT_NAME], c->val[type], val);
+       if (c->val[type])
+               free(c->val[type]);
+
+       c->val[type] = strdup(val);
+       if (c->val[type] == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       return 0;
+}
+
+int _appinfo_set_ptr_value(struct appinfo *c, enum appinfo_type type, void *val)
+{
+       if (!c || !val) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (type < AIT_START || type >= AIT_MAX)
+               return -1;
+
+       _D("%s : %p : %p", c->val[AIT_NAME], c->val[type], val);
+       if (appinfo_table[type].destructor && c->val[type] != NULL)
+               appinfo_table[type].destructor(c->val[type]);
+
+       c->val[type] = (char *)val;
+       return 0;
+}
+
+int _appinfo_set_int_value(struct appinfo *c, enum appinfo_type type, int val)
+{
+       if (!c) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (type < AIT_START || type >= AIT_MAX)
+               return -1;
+
+       _D("%s : %p : %d", c->val[AIT_NAME], c->val[type], val);
+
+       c->val[type] = (char *)GINT_TO_POINTER(val);
+       return 0;
+}
+
+static void __iter_cb(gpointer key, gpointer value, gpointer user_data)
+{
+       struct callback_info *cb_info = user_data;
+
+       if (cb_info == NULL)
+               return;
+
+       cb_info->cb(cb_info->user_data, key, value);
+}
+
+void _appinfo_foreach(uid_t uid, appinfo_iter_callback cb, void *user_data)
+{
+       struct user_appinfo *info;
+       struct callback_info cb_info = {
+               .cb = cb,
+               .user_data = user_data
+       };
+
+       if (!cb) {
+               _E("Invalid parameter");
+               return;
+       }
+
+       info = __find_user_appinfo(uid);
+       if (info == NULL)
+               return;
+
+       g_hash_table_foreach(info->tbl, __iter_cb, &cb_info);
+}
+
+int _appinfo_load(uid_t uid)
+{
+       struct user_appinfo *info;
+
+       info = __find_user_appinfo(uid);
+       if (info) {
+               _D("%d appinfo already exists", uid);
+               return 0;
+       }
+
+       info = __add_user_appinfo(uid);
+       if (info == NULL) {
+               _W("Failed to load appinfo - %d", uid);
+               return -1;
+       }
+
+       _D("loaded appinfo table for uid(%d)", uid);
+       return 0;
+}
+
+void _appinfo_unload(uid_t uid)
+{
+       struct user_appinfo *info;
+
+       info = __find_user_appinfo(uid);
+       if (info == NULL) {
+               _D("%d appinfo doesn't exist", uid);
+               return;
+       }
+
+       __remove_user_appinfo(uid);
+       _D("unloaded appinfo table for uid(%d)", uid);
+}
+
+struct appinfo_splash_image *_appinfo_find_splash_image(struct appinfo *c,
+               const char *name, bool landscape)
+{
+       struct appinfo_splash_screen *splash_screen;
+
+       if (!c || !name) {
+               _E("Invalid parameter");
+               return NULL;
+       }
+
+       splash_screen = (struct appinfo_splash_screen *)_appinfo_get_value(c,
+                       AIT_SPLASH_SCREEN);
+       if (!splash_screen)
+               return NULL;
+
+       if (landscape)
+               return g_hash_table_lookup(splash_screen->landscape, name);
+
+       return g_hash_table_lookup(splash_screen->portrait, name);
+}
+
+const char *_appinfo_splash_image_get_source(struct appinfo_splash_image *s)
+{
+       if (!s) {
+               _E("Invalid parameter");
+               return NULL;
+       }
+
+       return s->src;
+}
+
+const char *_appinfo_splash_image_get_type(struct appinfo_splash_image *s)
+{
+       if (!s) {
+               _E("Invalid paramter");
+               return NULL;
+       }
+
+       return s->type;
+}
+
+int _appinfo_splash_image_get_indicator_display(struct appinfo_splash_image *s)
+{
+       if (!s) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (!strcmp(s->indicatordisplay, "true"))
+               return 1;
+
+       return 0;
+}
+
+int _appinfo_splash_image_get_color_depth(struct appinfo_splash_image *s)
+{
+       int color_depth = 24; /* default */
+
+       if (!s) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (isdigit(s->color_depth[0]))
+               color_depth = atoi(s->color_depth);
+
+       return color_depth;
+}
diff --git a/src/lib/amd_config.c b/src/lib/amd_config.c
new file mode 100644 (file)
index 0000000..a1e9193
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <system_info.h>
+
+#include "amd_config.h"
+
+tizen_profile_t _get_tizen_profile(void)
+{
+       static tizen_profile_t profile = TIZEN_PROFILE_UNKNOWN;
+       char *profile_name = NULL;
+
+       if (__builtin_expect(profile != TIZEN_PROFILE_UNKNOWN, 1))
+               return profile;
+
+       system_info_get_platform_string("http://tizen.org/feature/profile",
+                       &profile_name);
+       if (profile_name == NULL)
+               return profile;
+
+       switch (*profile_name) {
+       case 'm':
+       case 'M':
+               profile = TIZEN_PROFILE_MOBILE;
+               break;
+       case 'w':
+       case 'W':
+               profile = TIZEN_PROFILE_WEARABLE;
+               break;
+       case 't':
+       case 'T':
+               profile = TIZEN_PROFILE_TV;
+               break;
+       case 'i':
+       case 'I':
+               profile = TIZEN_PROFILE_IVI;
+               break;
+       default: /* common or unknown ==> ALL ARE COMMON. */
+               profile = TIZEN_PROFILE_COMMON;
+               break;
+       }
+       free(profile_name);
+
+       return profile;
+}
diff --git a/src/lib/amd_cynara.c b/src/lib/amd_cynara.c
new file mode 100644 (file)
index 0000000..9247f57
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <malloc.h>
+#include <stdlib.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <glib.h>
+#include <glib-unix.h>
+#include <aul_sock.h>
+#include <aul_svc.h>
+#include <aul_svc_priv_key.h>
+#include <amd_request.h>
+#include <amd_appinfo.h>
+#include <aul.h>
+
+#include "amd_cynara.h"
+#include "amd_config.h"
+#include "amd_util.h"
+#include "amd_app_status.h"
+
+static cynara_ops __cynara_ops;
+static cynara_caller_info_ops __cynara_ci_ops;
+static GList *__pending_checkers;
+static GList *__pending_sub_checkers;
+
+struct checker_info {
+       const cynara_checker *checkers;
+       int cnt;
+};
+
+struct sub_checker_info {
+       char *name;
+       sub_checker_func func;
+};
+
+int _cynara_simple_checker(caller_info_h info, request_h req, void *data)
+{
+       if (__cynara_ops.check)
+               return __cynara_ops.check(info, req, data);
+
+       return AMD_CYNARA_ALLOWED;
+}
+
+int _cynara_check_privilege(request_h req, cynara_response_cb callback)
+{
+       if (__cynara_ops.check_async)
+               return __cynara_ops.check_async(req, callback);
+
+       return AMD_CYNARA_ALLOWED;
+}
+
+int _cynara_register_checkers(const cynara_checker *checkers, int cnt)
+{
+       struct checker_info *info;
+
+       if (__cynara_ops.register_checkers)
+               return __cynara_ops.register_checkers(checkers, cnt);
+
+       info = calloc(1, sizeof(struct checker_info));
+       if (!info) {
+               _E("Out-of-memory");
+               return -1;
+       }
+
+       info->checkers = checkers;
+       info->cnt = cnt;
+       __pending_checkers = g_list_append(__pending_checkers, info);
+
+       return 0;
+}
+
+const char *_cynara_caller_info_get_client(caller_info_h info)
+{
+       if (__cynara_ci_ops.get_client)
+               return __cynara_ci_ops.get_client(info);
+
+       return NULL;
+}
+
+int _cynara_sub_checker_add(const char *name, sub_checker_func func)
+{
+       struct sub_checker_info *sub_info;
+
+       if (__cynara_ops.sub_checker_add)
+               return __cynara_ops.sub_checker_add(name, func);
+
+       sub_info = calloc(1, sizeof(struct sub_checker_info));
+       if (!sub_info) {
+               _E("Out-of-memory");
+               return -1;
+       }
+
+       sub_info->name = strdup(name);
+       sub_info->func = func;
+
+       if (!sub_info->name) {
+               _E("Out-of-memory");
+               free(sub_info);
+               return -1;
+       }
+
+       __pending_sub_checkers = g_list_append(__pending_sub_checkers, sub_info);
+
+       return 0;
+}
+
+int _cynara_sub_checker_check(const char *name, caller_info_h info, request_h req)
+{
+       if (__cynara_ops.sub_checker_check)
+               return __cynara_ops.sub_checker_check(name, info, req);
+
+       return AMD_CYNARA_CONTINUE;
+}
+
+static void __clear_sub_checker_info(gpointer data)
+{
+       struct sub_checker_info *sub_info = data;
+
+       if (!data)
+               return;
+
+       free(sub_info->name);
+       free(sub_info);
+}
+
+static void __clear_pending_list(void)
+{
+       if (__pending_checkers) {
+               g_list_free_full(__pending_checkers, free);
+               __pending_checkers = NULL;
+       }
+
+       if (__pending_sub_checkers) {
+               g_list_free_full(__pending_sub_checkers, __clear_sub_checker_info);
+               __pending_sub_checkers = NULL;
+       }
+}
+
+int _cynara_register_ops(cynara_ops ops, cynara_caller_info_ops ci_ops)
+{
+       GList *i = __pending_checkers;
+       struct checker_info *info;
+       struct sub_checker_info *sub_info;
+
+       __cynara_ops = ops;
+       __cynara_ci_ops = ci_ops;
+       while (i) {
+               info = i->data;
+               if (__cynara_ops.register_checkers)
+                       __cynara_ops.register_checkers(info->checkers, info->cnt);
+
+               i = g_list_next(i);
+       }
+
+       i = __pending_sub_checkers;
+       while (i) {
+               sub_info = i->data;
+               if (__cynara_ops.sub_checker_add)
+                       __cynara_ops.sub_checker_add(sub_info->name, sub_info->func);
+
+               i = g_list_next(i);
+       }
+
+       __clear_pending_list();
+
+       return 0;
+}
+
+int _cynara_init(void)
+{
+       _D("cynara init");
+
+       return 0;
+}
+
+void _cynara_finish(void)
+{
+       _D("cynara fini");
+       __clear_pending_list();
+}
+
diff --git a/src/lib/amd_inotify.c b/src/lib/amd_inotify.c
new file mode 100644 (file)
index 0000000..efcbf1f
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/inotify.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "amd_config.h"
+#include "amd_util.h"
+#include "amd_inotify.h"
+
+#define INOTIFY_BUF (1024 * ((sizeof(struct inotify_event)) + 16))
+
+struct inotify_watch_info {
+       int wd;
+       inotify_watch_cb cb;
+       void *data;
+};
+
+struct inotify_info {
+       int fd;
+       GIOChannel *io;
+       guint id;
+       bool initialized;
+};
+
+static struct inotify_info __inotify;
+static GList *__watch_list;
+
+static void __destroy_inotify_watch_info(gpointer data)
+{
+       struct inotify_watch_info *info = (struct inotify_watch_info *)data;
+
+       if (info == NULL)
+               return;
+
+       if (info->wd > 0)
+               inotify_rm_watch(__inotify.fd, info->wd);
+       free(info);
+}
+
+static struct inotify_watch_info *__create_inotify_watch_info(const char *path,
+               uint32_t mask, inotify_watch_cb cb, void *data)
+{
+       struct inotify_watch_info *info;
+
+       info = calloc(1, sizeof(struct inotify_watch_info));
+       if (info == NULL) {
+               _E("Out of memory");
+               return NULL;
+       }
+
+       info->wd = inotify_add_watch(__inotify.fd, path, mask);
+       if (info->wd < 0) {
+               _E("Failed to add inotify watch, path(%s), errno(%d)",
+                               path, errno);
+               free(info);
+               return NULL;
+       }
+
+       info->cb = cb;
+       info->data = data;
+
+       return info;
+}
+
+static void __fini_inotify(void)
+{
+       if (__inotify.id) {
+               g_source_remove(__inotify.id);
+               __inotify.id = 0;
+       }
+
+       if (__inotify.io) {
+               g_io_channel_unref(__inotify.io);
+               __inotify.io = NULL;
+       }
+
+       if (__inotify.fd > 0) {
+               close(__inotify.fd);
+               __inotify.fd = 0;
+       }
+
+       __inotify.initialized = false;
+}
+
+static gboolean __inotify_watch_cb(GIOChannel *io, GIOCondition cond,
+               gpointer data)
+{
+       char buf[INOTIFY_BUF];
+       ssize_t len;
+       int i = 0;
+       struct inotify_event *e;
+       int fd = g_io_channel_unix_get_fd(io);
+       struct inotify_watch_info *info;
+       GList *iter;
+
+       len = read(fd, buf, sizeof(buf));
+       if (len < 0) {
+               _W("Failed to read from a inotify file descriptor");
+               return G_SOURCE_CONTINUE;
+       }
+
+       while (i < len) {
+               e = (struct inotify_event *)&buf[i];
+               if (e->len) {
+                       iter = g_list_first(__watch_list);
+                       while (iter) {
+                               info = (struct inotify_watch_info *)iter->data;
+                               iter = g_list_next(iter);
+                               if (info->wd == e->wd) {
+                                       if (!info->cb(e->name, info->data)) {
+                                               __watch_list = g_list_remove(
+                                                               __watch_list,
+                                                               info);
+                                               __destroy_inotify_watch_info(
+                                                               info);
+                                       }
+                               }
+                       }
+               }
+
+               i += offsetof(struct inotify_event, name) + e->len;
+               if (i >= INOTIFY_BUF)
+                       break;
+       }
+
+       return G_SOURCE_CONTINUE;
+}
+
+static int __init_inotify(void)
+{
+       GIOCondition cond = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP;
+
+       if (__inotify.initialized)
+               return 0;
+
+       __inotify.fd = inotify_init1(IN_CLOEXEC);
+       if (__inotify.fd < 0) {
+               _E("Failed to initialize inotify");
+               return -1;
+       }
+
+       __inotify.io = g_io_channel_unix_new(__inotify.fd);
+       if (__inotify.io == NULL) {
+               _E("Failed to create a new GIOChannel");
+               __fini_inotify();
+               return -1;
+       }
+
+       __inotify.id = g_io_add_watch(__inotify.io, cond,
+                       __inotify_watch_cb, NULL);
+       if (__inotify.id == 0) {
+               _E("Failed to add GIOChannel watch");
+               __fini_inotify();
+               return -1;
+       }
+
+       __inotify.initialized = true;
+
+       return 0;
+}
+
+int _inotify_add_watch(const char *path, uint32_t mask,
+               inotify_watch_cb callback, void *data)
+{
+       struct inotify_watch_info *info;
+
+       if (path == NULL || callback == NULL) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (__init_inotify() < 0)
+               return -1;
+
+       info = __create_inotify_watch_info(path, mask, callback, data);
+       if (info == NULL)
+               return -1;
+
+       __watch_list = g_list_append(__watch_list, info);
+
+       return info->wd;
+}
+
+void _inotify_rm_watch(int wd)
+{
+       struct inotify_watch_info *info;
+       GList *iter;
+
+       iter = g_list_first(__watch_list);
+       while (iter) {
+               info = (struct inotify_watch_info *)iter->data;
+               iter = g_list_next(iter);
+               if (info->wd == wd) {
+                       __watch_list = g_list_remove(__watch_list, info);
+                       __destroy_inotify_watch_info(info);
+                       break;
+               }
+       }
+}
+
+int _inotify_init(void)
+{
+       _D("inotify init");
+
+       __init_inotify();
+
+       return 0;
+}
+
+void _inotify_fini(void)
+{
+       _D("inotify fini");
+
+       if (__watch_list)
+               g_list_free_full(__watch_list, __destroy_inotify_watch_info);
+
+       __fini_inotify();
+}
diff --git a/src/lib/amd_launch.c b/src/lib/amd_launch.c
new file mode 100644 (file)
index 0000000..478317d
--- /dev/null
@@ -0,0 +1,2607 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <signal.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <aul.h>
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pkgmgr-info.h>
+#include <poll.h>
+#include <tzplatform_config.h>
+#include <cert-svc/ccert.h>
+#include <cert-svc/cinstance.h>
+#include <aul_sock.h>
+#include <aul_svc.h>
+#include <aul_svc_priv_key.h>
+#include <ttrace.h>
+#include <app2ext_interface.h>
+#include <vconf.h>
+
+#include "amd_launch.h"
+#include "amd_appinfo.h"
+#include "amd_app_status.h"
+#include "amd_util.h"
+#include "app_signal.h"
+#include "amd_socket.h"
+#include "amd_app_com.h"
+#include "amd_suspend.h"
+#include "amd_signal.h"
+#include "amd_app_property.h"
+#include "amd_request.h"
+#include "amd_noti.h"
+#include "amd_cynara.h"
+#include "amd_launchpad.h"
+
+#define DAC_ACTIVATE
+
+#define TERM_WAIT_SEC 3
+#define INIT_PID 1
+
+#define AUL_PR_NAME 16
+#define OSP_K_LAUNCH_TYPE "__OSP_LAUNCH_TYPE__"
+#define OSP_V_LAUNCH_TYPE_DATACONTROL "datacontrol"
+#define APP_CONTROL_OPERATION_MAIN "http://tizen.org/appcontrol/operation/main"
+#define PENDING_REQUEST_TIMEOUT 5000 /* msec */
+#define SYSTEM_REQUEST_TIMEOUT 90000 /* msec */
+#define PENDING_MESSAGE_MAX_CNT 100
+
+struct launch_s {
+       const char *appid;
+       const struct appinfo *ai;
+       const char *instance_id;
+       int pid;
+       bool new_process;
+       bool is_subapp;
+       int prelaunch_attr;
+       int bg_category;
+       bool bg_allowed;
+       bool bg_launch;
+       bool new_instance;
+       app_status_h app_status;
+       bool debug_mode;
+};
+
+struct fgmgr {
+       guint tid;
+       int pid;
+};
+
+static GList *_fgmgr_list;
+static int __pid_of_last_launched_ui_app;
+static int __focused_pid;
+
+static void __set_reply_handler(int fd, int pid, request_h req, int cmd);
+static int __nofork_processing(int cmd, int pid, bundle *kb, request_h req);
+
+static void __set_stime(bundle *kb)
+{
+       struct timeval tv;
+       char tmp[MAX_LOCAL_BUFSZ];
+
+       gettimeofday(&tv, NULL);
+       snprintf(tmp, MAX_LOCAL_BUFSZ, "%ld/%ld", tv.tv_sec, tv.tv_usec);
+       bundle_add(kb, AUL_K_STARTTIME, tmp);
+}
+
+int _launch_start_app_local_with_bundle(uid_t uid, const char *appid,
+               bundle *kb)
+{
+       request_h req;
+       int r;
+       bool dummy;
+       bool dummy_mode;
+
+       __set_stime(kb);
+       bundle_add(kb, AUL_K_APPID, appid);
+       req = _request_create_local(APP_START, uid, getpid(), kb);
+       if (req == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       r = _launch_start_app(appid, req, &dummy, &dummy_mode, false);
+       _request_free_local(req);
+
+       return r;
+}
+
+int _launch_start_app_local(uid_t uid, const char *appid)
+{
+       int pid;
+       bundle *kb;
+
+       kb = bundle_create();
+       if (kb == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       pid = _launch_start_app_local_with_bundle(uid, appid, kb);
+       bundle_free(kb);
+
+       return pid;
+}
+
+int _launch_start_onboot_app_local(uid_t uid, const char *appid,
+               struct appinfo *ai)
+{
+       int ret = -1;
+       int enable = 1;
+       app_status_h app_status;
+       const char *comp_type;
+       const char *onboot;
+
+       if (appid == NULL || ai == NULL)
+               return -1;
+
+       comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+       if (comp_type == NULL || strcmp(comp_type, APP_TYPE_SERVICE) != 0)
+               return -1;
+
+       onboot = _appinfo_get_value(ai, AIT_ONBOOT);
+       if (onboot == NULL || strcmp(onboot, "true") != 0)
+               return -1;
+
+       ret = _appinfo_get_int_value(ai, AIT_ENABLEMENT, &enable);
+       if (ret == 0 && !(enable & APP_ENABLEMENT_MASK_ACTIVE))
+               return -1;
+
+       app_status = _app_status_find_by_appid(appid, uid);
+       if (_app_status_is_running(app_status) > 0)
+               return -1;
+
+       _D("start app %s from user %d by onboot", appid, uid);
+       return _launch_start_app_local(uid, appid);
+}
+
+int _terminate_app_local(uid_t uid, int pid)
+{
+       request_h req;
+       int ret;
+
+       req = _request_create_local(APP_TERM_BY_PID, uid, getpid(), NULL);
+       if (req == NULL) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       aul_send_app_terminate_request_signal(pid, NULL, NULL, NULL);
+       ret = _term_app(pid, req);
+       _request_free_local(req);
+
+       return ret;
+}
+
+int _send_to_sigkill(int pid)
+{
+       int pgid;
+
+       if (pid <= 1)
+               return -1;
+
+       pgid = getpgid(pid);
+       if (pgid <= 1)
+               return -1;
+
+       if (killpg(pgid, SIGKILL) < 0)
+               return -1;
+
+       return 0;
+}
+
+int _resume_app(int pid, request_h req)
+{
+       int dummy;
+       int ret;
+
+       ret = aul_sock_send_raw(pid, _request_get_target_uid(req),
+                       APP_RESUME_BY_PID, (unsigned char *)&dummy, 0,
+                       AUL_SOCK_ASYNC);
+       if (ret < 0) {
+               if (ret == -EAGAIN) {
+                       _E("resume packet timeout error");
+               } else {
+                       _E("raise failed - %d resume fail\n", pid);
+                       _E("we will term the app - %d\n", pid);
+                       _send_to_sigkill(pid);
+                       ret = -1;
+               }
+               _request_send_result(req, ret);
+       }
+       _D("resume done\n");
+
+       if (ret > 0)
+               __set_reply_handler(ret, pid, req, APP_RESUME_BY_PID);
+
+       return ret;
+}
+
+int _pause_app(int pid, request_h req)
+{
+       int dummy;
+       int ret;
+
+       ret = aul_sock_send_raw(pid, _request_get_target_uid(req),
+                       APP_PAUSE_BY_PID, (unsigned char *)&dummy, 0,
+                       AUL_SOCK_ASYNC);
+       if (ret < 0) {
+               if (ret == -EAGAIN) {
+                       _E("pause packet timeout error");
+               } else {
+                       _E("iconify failed - %d pause fail", pid);
+                       _E("we will term the app - %d", pid);
+                       _send_to_sigkill(pid);
+                       ret = -1;
+               }
+               _request_send_result(req, ret);
+       }
+       _D("pause done");
+
+       if (ret > 0)
+               __set_reply_handler(ret, pid, req, APP_PAUSE_BY_PID);
+
+       return ret;
+}
+
+int _term_sub_app(int pid, uid_t uid)
+{
+       int dummy;
+       int ret;
+
+       ret = aul_sock_send_raw(pid, uid, APP_TERM_BY_PID_ASYNC,
+                       (unsigned char *)&dummy, 0, AUL_SOCK_NOREPLY);
+       if (ret < 0) {
+               _E("terminate packet send error - use SIGKILL");
+               if (_send_to_sigkill(pid) < 0) {
+                       _E("fail to killing - %d\n", pid);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int _term_app(int pid, request_h req)
+{
+       int dummy;
+       int ret;
+       uid_t uid = _request_get_target_uid(req);
+
+       _noti_send("launch.term_app.start", pid, 0, req, NULL);
+       ret = aul_sock_send_raw(pid, uid, APP_TERM_BY_PID,
+                       (unsigned char *)&dummy, 0, AUL_SOCK_ASYNC);
+       if (ret < 0) {
+               _D("terminate packet send error - use SIGKILL");
+               if (_send_to_sigkill(pid) < 0) {
+                       _E("fail to killing - %d\n", pid);
+                       _request_send_result(req, -1);
+                       return -1;
+               }
+               _request_send_result(req, 0);
+       }
+       _D("term done\n");
+
+       if (ret > 0)
+               __set_reply_handler(ret, pid, req, APP_TERM_BY_PID);
+
+       return 0;
+}
+
+int _term_req_app(int pid, request_h req)
+{
+       int dummy;
+       int ret;
+
+       ret = aul_sock_send_raw(pid, _request_get_target_uid(req),
+                       APP_TERM_REQ_BY_PID, (unsigned char *)&dummy, 0,
+                       AUL_SOCK_ASYNC);
+       if (ret < 0) {
+               _D("terminate req send error");
+               _request_send_result(req, ret);
+       }
+
+       if (ret > 0)
+               __set_reply_handler(ret, pid, req, APP_TERM_REQ_BY_PID);
+
+       return 0;
+}
+
+int _term_bgapp(int pid, request_h req)
+{
+       int dummy;
+       int ret;
+       uid_t uid = _request_get_target_uid(req);
+
+       _noti_send("launch.term_bgapp.start", pid, 0, req, NULL);
+       ret = aul_sock_send_raw(pid, uid, APP_TERM_BGAPP_BY_PID,
+                       (unsigned char *)&dummy, sizeof(int), AUL_SOCK_ASYNC);
+       if (ret < 0) {
+               _D("terminate packet send error - use SIGKILL");
+               if (_send_to_sigkill(pid) < 0) {
+                       _E("fail to killing - %d", pid);
+                       _request_send_result(req, -1);
+                       return -1;
+               }
+               _request_send_result(req, 0);
+       }
+       _D("term_bgapp done");
+
+       if (ret > 0)
+               __set_reply_handler(ret, pid, req, APP_TERM_BGAPP_BY_PID);
+
+       return 0;
+}
+
+int _term_app_v2(int pid, request_h req, bool *pend)
+{
+       int dummy;
+       int ret;
+       uid_t uid = _request_get_target_uid(req);
+
+       _noti_send("launch.term_app.start", pid, 0, req, NULL);
+       ret = aul_sock_send_raw(pid, uid, APP_TERM_BY_PID_SYNC,
+                       (unsigned char *)&dummy, 0,
+                       AUL_SOCK_ASYNC | AUL_SOCK_NOREPLY);
+       if (ret < 0) {
+               _D("Failed to send the terminate packet - use SIGKILL");
+               if (_send_to_sigkill(pid) < 0) {
+                       _E("Failed to kill - %d\n", pid);
+                       _request_send_result(req, -1);
+                       return -1;
+               }
+       }
+       _D("term v2 done");
+
+       if (pend)
+               *pend = true;
+
+       return 0;
+}
+
+static int __fake_launch_app(int cmd, int pid, bundle *kb, request_h req)
+{
+       int ret;
+
+       ret = aul_sock_send_bundle(pid, _request_get_target_uid(req), cmd, kb,
+                       AUL_SOCK_ASYNC);
+       if (ret < 0) {
+               _E("error request fake launch - error code = %d", ret);
+               _request_send_result(req, ret);
+       }
+
+       if (ret > 0)
+               __set_reply_handler(ret, pid, req, cmd);
+
+       return ret;
+}
+
+static int __fake_launch_app_async(int cmd, int pid, bundle *kb, request_h req)
+{
+       int ret;
+
+       ret = aul_sock_send_bundle(pid, _request_get_target_uid(req), cmd, kb,
+                       AUL_SOCK_ASYNC);
+       if (ret < 0) {
+               _E("error request fake launch - error code = %d", ret);
+               _request_send_result(req, ret);
+       }
+
+       if (ret > 0) {
+               _send_result_to_client(_request_remove_fd(req), pid);
+               __set_reply_handler(ret, pid, req, cmd);
+       }
+
+       return ret;
+}
+
+static gboolean __au_glib_check(GSource *src)
+{
+       GSList *fd_list;
+       GPollFD *tmp;
+
+       fd_list = src->poll_fds;
+       do {
+               tmp = (GPollFD *) fd_list->data;
+               if ((tmp->revents & (POLLIN | POLLPRI)))
+                       return TRUE;
+               fd_list = fd_list->next;
+       } while (fd_list);
+
+       return FALSE;
+}
+
+static gboolean __au_glib_dispatch(GSource *src, GSourceFunc callback,
+               gpointer data)
+{
+       callback(data);
+       return TRUE;
+}
+
+static gboolean __au_glib_prepare(GSource *src, gint *timeout)
+{
+       return FALSE;
+}
+
+static GSourceFuncs funcs = {
+       .prepare = __au_glib_prepare,
+       .check = __au_glib_check,
+       .dispatch = __au_glib_dispatch,
+       .finalize = NULL
+};
+
+struct reply_info {
+       GSource *src;
+       GPollFD *gpollfd;
+       guint timer_id;
+       int clifd;
+       int pid;
+       int cmd;
+};
+
+static gboolean __reply_handler(gpointer data)
+{
+       struct reply_info *r_info = (struct reply_info *)data;
+       int fd = r_info->gpollfd->fd;
+       int len;
+       int res = 0;
+       int clifd = r_info->clifd;
+       int pid = r_info->pid;
+       char err_buf[1024];
+
+       len = recv(fd, &res, sizeof(int), 0);
+       if (len == -1) {
+               if (errno == EAGAIN) {
+                       _E("recv timeout : %s",
+                               strerror_r(errno, err_buf, sizeof(err_buf)));
+                       res = -EAGAIN;
+               } else {
+                       _E("recv error : %s",
+                               strerror_r(errno, err_buf, sizeof(err_buf)));
+                       res = -ECOMM;
+               }
+       }
+       close(fd);
+
+       if (res >= 0)
+               res = pid;
+       _send_result_to_client(clifd, res);
+
+       _D("listen fd : %d , send fd : %d, pid : %d", fd, clifd, pid);
+
+       g_source_remove(r_info->timer_id);
+       g_source_remove_poll(r_info->src, r_info->gpollfd);
+       g_source_destroy(r_info->src);
+       g_source_unref(r_info->src);
+       g_free(r_info->gpollfd);
+       free(r_info);
+
+       return TRUE;
+}
+
+static gboolean __recv_timeout_handler(gpointer data)
+{
+       struct reply_info *r_info = (struct reply_info *)data;
+       int fd = r_info->gpollfd->fd;
+       int clifd = r_info->clifd;
+       const char *appid;
+       const struct appinfo *ai;
+       const char *taskmanage;
+       app_status_h app_status;
+       uid_t uid;
+       int ret = -EAGAIN;
+
+       _E("application is not responding: pid(%d) cmd(%d)",
+                       r_info->pid, r_info->cmd);
+       close(fd);
+
+       switch (r_info->cmd) {
+       case APP_OPEN:
+       case APP_RESUME:
+       case APP_START:
+       case APP_START_RES:
+       case APP_START_ASYNC:
+       case APP_START_RES_ASYNC:
+               app_status = _app_status_find(r_info->pid);
+               if (app_status == NULL)
+                       break;
+
+               uid = _app_status_get_uid(app_status);
+               appid = _app_status_get_appid(app_status);
+               ai = _appinfo_find(uid, appid);
+               if (ai == NULL)
+                       break;
+               taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE);
+               if (taskmanage && strcmp(taskmanage, "true") == 0)
+                       _signal_send_watchdog(r_info->pid, SIGKILL);
+               break;
+       case APP_TERM_BY_PID:
+       case APP_TERM_BGAPP_BY_PID:
+               if (_send_to_sigkill(r_info->pid) == 0)
+                       ret = 0;
+               break;
+       }
+
+       _send_result_to_client(clifd, ret);
+       g_source_remove_poll(r_info->src, r_info->gpollfd);
+       g_source_destroy(r_info->src);
+       g_source_unref(r_info->src);
+       g_free(r_info->gpollfd);
+       free(r_info);
+
+       return FALSE;
+}
+
+static void __set_reply_handler(int fd, int pid, request_h req, int cmd)
+{
+       GPollFD *gpollfd;
+       GSource *src;
+       struct reply_info *r_info;
+       struct timeval tv;
+
+       src = g_source_new(&funcs, sizeof(GSource));
+       if (src == NULL) {
+               _E("Out of memory");
+               return;
+       }
+
+       gpollfd = (GPollFD *)g_malloc(sizeof(GPollFD));
+       if (gpollfd == NULL) {
+               _E("Out of memory");
+               g_source_unref(src);
+               return;
+       }
+
+       gpollfd->events = POLLIN;
+       gpollfd->fd = fd;
+
+       r_info = malloc(sizeof(*r_info));
+       if (r_info == NULL) {
+               _E("out of memory");
+               g_free(gpollfd);
+               g_source_unref(src);
+               return;
+       }
+
+       r_info->clifd = _request_remove_fd(req);
+       r_info->pid = pid;
+       r_info->src = src;
+       r_info->gpollfd = gpollfd;
+       r_info->cmd = cmd;
+
+       tv = aul_sock_get_rcv_timeval();
+       r_info->timer_id = g_timeout_add_seconds(tv.tv_sec,
+                       __recv_timeout_handler, (gpointer)r_info);
+       g_source_add_poll(src, gpollfd);
+       g_source_set_callback(src, (GSourceFunc)__reply_handler,
+                       (gpointer)r_info, NULL);
+       g_source_set_priority(src, G_PRIORITY_DEFAULT);
+       g_source_attach(src, NULL);
+
+       _D("listen fd : %d, send fd : %d", fd, r_info->clifd);
+}
+
+static void __check_request_for_app_boosting(request_h req)
+{
+       int cmd = _request_get_cmd(req);
+       bundle *kb = _request_get_bundle(req);
+       int lcd_status = 0;
+       const char *op;
+
+       if (kb == NULL)
+               return;
+
+       op = bundle_get_val(kb, AUL_SVC_K_OPERATION);
+       if ((op && !strcmp(op, APP_CONTROL_OPERATION_MAIN)) ||
+                       cmd == APP_OPEN) {
+               vconf_get_int(VCONFKEY_PM_STATE, &lcd_status);
+               if (lcd_status == VCONFKEY_PM_STATE_LCDOFF)
+                       _D("LCD OFF: Skip app launch boost");
+               else
+                       _signal_send_cpu_boost(APP_BOOSTING_PERIOD);
+       }
+}
+
+static int __nofork_processing(int cmd, int pid, bundle *kb, request_h req)
+{
+       int ret;
+
+       __check_request_for_app_boosting(req);
+
+       switch (cmd) {
+       case APP_OPEN:
+       case APP_RESUME:
+               _D("resume app's pid : %d\n", pid);
+               ret = _resume_app(pid, req);
+               if (ret < 0)
+                       _E("__resume_app failed. error code = %d", ret);
+               _D("resume app done");
+               break;
+       case APP_START:
+       case APP_START_RES:
+               _D("fake launch pid : %d\n", pid);
+               ret = __fake_launch_app(cmd, pid, kb, req);
+               if (ret < 0)
+                       _E("fake_launch failed. error code = %d", ret);
+               _D("fake launch done");
+               break;
+       case APP_START_ASYNC:
+       case APP_START_RES_ASYNC:
+               ret = __fake_launch_app_async(cmd, pid, kb, req);
+               if (ret < 0)
+                       _E("fake_launch_async failed. error code = %d", ret);
+               _D("fake launch async done");
+               break;
+       default:
+               _E("unknown command: %d", cmd);
+               ret = -1;
+       }
+
+       return ret;
+}
+
+static int __compare_signature(const struct appinfo *ai, int cmd,
+               uid_t caller_uid, const char *appid, const char *caller_appid)
+{
+       const char *permission;
+       const struct appinfo *caller_ai;
+       const char *preload;
+       const char *api_version;
+       pkgmgrinfo_cert_compare_result_type_e compare_result;
+
+       permission = _appinfo_get_value(ai, AIT_PERM);
+       if (permission && strcmp(permission, "signature") == 0) {
+               if (caller_uid != 0 && (cmd == APP_START ||
+                                       cmd == APP_START_RES ||
+                                       cmd == APP_START_ASYNC ||
+                                       cmd == APP_START_RES_ASYNC)) {
+                       caller_ai = _appinfo_find(caller_uid, caller_appid);
+                       preload = _appinfo_get_value(caller_ai, AIT_PRELOAD);
+                       if (!preload || strcmp(preload, "true") == 0)
+                               return 0;
+
+                       api_version = _appinfo_get_value(caller_ai,
+                                       AIT_API_VERSION);
+                       if (api_version && strverscmp(api_version, "2.4") < 0)
+                               return 0;
+
+                       /* is admin is global */
+                       if (caller_uid != GLOBAL_USER) {
+                               pkgmgrinfo_pkginfo_compare_usr_app_cert_info(
+                                               caller_appid, appid,
+                                               caller_uid, &compare_result);
+                       } else {
+                               pkgmgrinfo_pkginfo_compare_app_cert_info(
+                                               caller_appid, appid,
+                                               &compare_result);
+                       }
+
+                       if (compare_result != PMINFO_CERT_COMPARE_MATCH)
+                               return -EILLEGALACCESS;
+               }
+       }
+
+       return 0;
+}
+
+static void __prepare_to_suspend(int pid, uid_t uid)
+{
+       int dummy = 0;
+
+       SECURE_LOGD("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+       aul_sock_send_raw(pid, uid, APP_SUSPEND, (unsigned char *)&dummy,
+                       sizeof(int), AUL_SOCK_NOREPLY);
+}
+
+static void __prepare_to_wake_services(int pid, uid_t uid)
+{
+       int dummy = 0;
+
+       SECURE_LOGD("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+       aul_sock_send_raw(pid, uid, APP_WAKE, (unsigned char *)&dummy,
+                       sizeof(int), AUL_SOCK_NOREPLY);
+}
+
+static gboolean __check_service_only(gpointer user_data)
+{
+       int pid = GPOINTER_TO_INT(user_data);
+       app_status_h app_status;
+
+       SECURE_LOGD("[__SUSPEND__] pid :%d", pid);
+       app_status = _app_status_find(pid);
+       _app_status_check_service_only(app_status,
+                       __prepare_to_suspend);
+
+       return FALSE;
+}
+
+static char *__get_cert_value_from_pkginfo(const char *pkgid, uid_t uid)
+{
+       int ret;
+       const char *cert_value;
+       char *ret_cert;
+       pkgmgrinfo_certinfo_h certinfo;
+
+       ret = pkgmgrinfo_pkginfo_create_certinfo(&certinfo);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to create certinfo");
+               return NULL;
+       }
+
+       ret = pkgmgrinfo_pkginfo_load_certinfo(pkgid, certinfo, uid);
+       if (ret != PMINFO_R_OK) {
+               _E("Failed to load certinfo");
+               pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
+               return NULL;
+       }
+
+       ret = pkgmgrinfo_pkginfo_get_cert_value(certinfo,
+                       PMINFO_DISTRIBUTOR_ROOT_CERT, &cert_value);
+       if (ret != PMINFO_R_OK || cert_value == NULL) {
+               _E("Failed to get cert value");
+               pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
+               return NULL;
+       }
+
+       ret_cert = strdup(cert_value);
+       pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
+
+       return ret_cert;
+}
+
+static int __get_visibility_from_certsvc(const char *cert_value)
+{
+       int ret;
+       CertSvcInstance instance;
+       CertSvcCertificate certificate;
+       CertSvcVisibility visibility = CERTSVC_VISIBILITY_PUBLIC;
+
+       if (cert_value == NULL)
+               return (int)visibility;
+
+       ret = certsvc_instance_new(&instance);
+       if (ret != CERTSVC_SUCCESS) {
+               _E("certsvc_instance_new() is failed.");
+               return (int)visibility;
+       }
+
+       ret = certsvc_certificate_new_from_memory(instance,
+                       (const unsigned char *)cert_value,
+                       strlen(cert_value),
+                       CERTSVC_FORM_DER_BASE64,
+                       &certificate);
+       if (ret != CERTSVC_SUCCESS) {
+               _E("certsvc_certificate_new_from_memory() is failed.");
+               certsvc_instance_free(instance);
+               return (int)visibility;
+       }
+
+       ret = certsvc_certificate_get_visibility(certificate, &visibility);
+       if (ret != CERTSVC_SUCCESS)
+               _E("certsvc_certificate_get_visibility() is failed.");
+
+       certsvc_certificate_free(certificate);
+       certsvc_instance_free(instance);
+
+       return (int)visibility;
+}
+
+static int __check_allowed_appid(const char *callee_appid,
+               const char *caller_appid, uid_t uid)
+{
+       app_property_h app_property;
+       GList *list;
+       GList *iter;
+       char *allowed_appid;
+
+       app_property = _app_property_find(uid);
+       if (app_property == NULL)
+               return -1;
+
+       list = _app_property_get_allowed_app_list(app_property, callee_appid);
+       iter = g_list_first(list);
+       while (iter) {
+               allowed_appid = (char *)iter->data;
+               if (allowed_appid && strcmp(allowed_appid, caller_appid) == 0) {
+                       _D("allowed appid(%s), appid(%s)",
+                                       allowed_appid, callee_appid);
+                       return 0;
+               }
+
+               iter = g_list_next(iter);
+       }
+
+       return -1;
+}
+
+static int __check_execute_permission(const char *callee_pkgid,
+               const char *caller_appid, uid_t caller_uid, bundle *kb)
+{
+       struct appinfo *ai;
+       const char *caller_pkgid;
+       const char *launch_type;
+       const char *v;
+       const char *callee_appid = bundle_get_val(kb, AUL_K_APPID);
+       char num[256];
+       int vi_num;
+       int visibility;
+       char *cert_value;
+       int ret;
+
+       if (callee_pkgid == NULL)
+               return -1;
+
+       ai = _appinfo_find(caller_uid, caller_appid);
+       if (ai == NULL)
+               return 0;
+
+       caller_pkgid = _appinfo_get_value(ai, AIT_PKGID);
+       if (caller_pkgid == NULL)
+               return 0;
+
+       if (strcmp(caller_pkgid, callee_pkgid) == 0)
+               return 0;
+
+       ret = __check_allowed_appid(callee_appid, caller_appid, caller_uid);
+       if (ret == 0)
+               return 0;
+
+       launch_type = bundle_get_val(kb, OSP_K_LAUNCH_TYPE);
+       if (launch_type == NULL
+               || strcmp(launch_type, OSP_V_LAUNCH_TYPE_DATACONTROL) != 0) {
+               v = _appinfo_get_value(ai, AIT_VISIBILITY);
+               if (v == NULL) {
+                       cert_value = __get_cert_value_from_pkginfo(caller_pkgid,
+                                       caller_uid);
+                       vi_num = __get_visibility_from_certsvc(cert_value);
+                       if (cert_value)
+                               free(cert_value);
+
+                       snprintf(num, sizeof(num), "%d", vi_num);
+                       _appinfo_set_value(ai, AIT_VISIBILITY, num);
+                       v = num;
+               }
+
+               visibility = atoi(v);
+               if (!(visibility & CERTSVC_VISIBILITY_PLATFORM)) {
+                       _E("Couldn't launch service app in other packages");
+                       return -EREJECTED;
+               }
+       }
+
+       return 0;
+}
+
+static gboolean __fg_timeout_handler(gpointer data)
+{
+       struct fgmgr *fg = data;
+       app_status_h app_status;
+
+       if (!fg)
+               return FALSE;
+
+       app_status = _app_status_find(fg->pid);
+       if (app_status == NULL)
+               return FALSE;
+
+       _W("%d is running in the background", fg->pid);
+       _app_status_update_status(app_status, STATUS_BG, true, true);
+
+       _fgmgr_list = g_list_remove(_fgmgr_list, fg);
+       free(fg);
+
+       return FALSE;
+}
+
+static int __launch_add_fgmgr(int pid)
+{
+       struct fgmgr *fg;
+
+       fg = calloc(1, sizeof(struct fgmgr));
+       if (!fg) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       fg->pid = pid;
+       fg->tid = g_timeout_add(5000, __fg_timeout_handler, fg);
+
+       _fgmgr_list = g_list_append(_fgmgr_list, fg);
+
+       return 0;
+}
+
+static void __launch_remove_fgmgr(int pid)
+{
+       GList *iter = NULL;
+       struct fgmgr *fg;
+
+       if (pid < 0)
+               return;
+
+       for (iter = _fgmgr_list; iter != NULL; iter = g_list_next(iter)) {
+               fg = (struct fgmgr *)iter->data;
+               if (fg->pid == pid) {
+                       g_source_remove(fg->tid);
+                       _fgmgr_list = g_list_remove(_fgmgr_list, fg);
+                       free(fg);
+                       return;
+               }
+       }
+}
+
+static int __send_hint_for_visibility(uid_t uid)
+{
+       bundle *b;
+       int ret;
+
+       b = bundle_create();
+       if (b == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       ret = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK, uid,
+                       PAD_CMD_VISIBILITY, b);
+       bundle_free(b);
+       __pid_of_last_launched_ui_app = 0;
+
+       return ret;
+}
+
+static int __app_status_handler(int pid, int status, void *data)
+{
+       const char *appid;
+       int old_status;
+       const struct appinfo *ai;
+       app_status_h app_status;
+       uid_t uid;
+
+       _W("pid(%d) status(%d)", pid, status);
+       app_status = _app_status_find(pid);
+       if (app_status == NULL)
+               return 0;
+
+       old_status = _app_status_get_status(app_status);
+       if (old_status == STATUS_DYING && old_status != PROC_STATUS_LAUNCH)
+               return 0;
+
+       uid = _app_status_get_uid(app_status);
+       switch (status) {
+       case PROC_STATUS_FG:
+               __launch_remove_fgmgr(pid);
+               _app_status_update_status(app_status, STATUS_VISIBLE, false,
+                               true);
+               _suspend_remove_timer(pid);
+
+               if (pid == __pid_of_last_launched_ui_app)
+                       __send_hint_for_visibility(uid);
+
+               _noti_send("launch.status.fg", pid, uid, app_status, NULL);
+               break;
+       case PROC_STATUS_BG:
+               _app_status_update_status(app_status, STATUS_BG, false, true);
+               appid = _app_status_get_appid(app_status);
+               ai = _appinfo_find(uid, appid);
+               if (!_suspend_is_allowed_background(ai)) {
+                       __prepare_to_suspend(pid, uid);
+                       _suspend_add_timer(pid);
+               }
+               _noti_send("launch.status.bg", pid, uid, app_status, NULL);
+               break;
+       case PROC_STATUS_FOCUS:
+               __focused_pid = pid;
+               _noti_send("launch.status.focus", pid, uid, app_status, NULL);
+               break;
+
+       case PROC_STATUS_HIDE:
+               _app_status_update_status(app_status, STATUS_BG, false, false);
+               _noti_send("launch.status.hide", pid, uid, app_status, NULL);
+               break;
+
+       case PROC_STATUS_LAUNCH:
+               _signal_send_cpu_boost(APP_BOOSTING_STOP);
+               appid = _app_status_get_appid(app_status);
+               if (appid)
+                       LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]", appid);
+               break;
+
+       }
+
+       return 0;
+}
+
+void _launch_set_focused_pid(int pid)
+{
+       __focused_pid = pid;
+}
+
+int _launch_get_focused_pid(void)
+{
+       return __focused_pid;
+}
+
+static int __listen_app_status_signal(void *data)
+{
+       int ret;
+
+       ret = aul_listen_app_status_signal(__app_status_handler, data);
+       if (ret < 0)
+               return -1;
+
+       return 0;
+}
+
+static void __set_effective_appid(uid_t uid, bundle *kb)
+{
+       const struct appinfo *ai;
+       const struct appinfo *effective_ai;
+       const char *appid;
+       const char *effective_appid;
+       const char *pkgid;
+       const char *effective_pkgid;
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       if (appid == NULL)
+               return;
+
+       ai = _appinfo_find(uid, appid);
+       if (ai == NULL)
+               return;
+
+       bundle_del(kb, AUL_SVC_K_PKG_NAME);
+       bundle_add(kb, AUL_SVC_K_PKG_NAME, appid);
+
+       effective_appid = _appinfo_get_value(ai, AIT_EFFECTIVE_APPID);
+       if (effective_appid == NULL)
+               return;
+
+       effective_ai = _appinfo_find(uid, effective_appid);
+       if (effective_ai == NULL)
+               return;
+
+       pkgid = _appinfo_get_value(ai, AIT_PKGID);
+       effective_pkgid = _appinfo_get_value(effective_ai, AIT_PKGID);
+       if (pkgid && effective_pkgid && strcmp(pkgid, effective_pkgid) == 0) {
+               _D("use effective appid instead of the real appid");
+               bundle_del(kb, AUL_K_APPID);
+               bundle_add(kb, AUL_K_APPID, effective_appid);
+       }
+}
+
+static void __set_real_appid(uid_t uid, bundle *kb)
+{
+       const char *alias_appid;
+       const char *appid;
+       const char *alias_info;
+       app_property_h app_property;
+
+       alias_appid = bundle_get_val(kb, AUL_K_APPID);
+       if (alias_appid == NULL)
+               return;
+
+       alias_info = bundle_get_val(kb, AUL_SVC_K_ALIAS_INFO);
+       if (alias_info && strcmp(alias_info, "disable") == 0)
+               return;
+
+       app_property = _app_property_find(uid);
+       if (app_property == NULL)
+               return;
+
+       appid = _app_property_get_real_appid(app_property, alias_appid);
+       if (appid == NULL)
+               return;
+
+       _D("alias_appid(%s), appid(%s)", alias_appid, appid);
+       bundle_del(kb, AUL_K_ORG_APPID);
+       bundle_add(kb, AUL_K_ORG_APPID, alias_appid);
+       bundle_del(kb, AUL_K_APPID);
+       bundle_add(kb, AUL_K_APPID, appid);
+}
+
+static int __dispatch_app_start(request_h req)
+{
+       const char *appid;
+       int ret;
+       bundle *kb;
+       bool pending = false;
+       bool bg_launch = false;
+       request_reply_h reply;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       __set_real_appid(_request_get_target_uid(req), kb);
+       __set_effective_appid(_request_get_target_uid(req), kb);
+
+       if (_noti_send("launch.app_start.hook", 0, 0, req, NULL) < 0)
+               return 0;
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       ret = _launch_start_app(appid, req, &pending, &bg_launch, false);
+       if (ret <= 0)
+               _noti_send("launch.fail", ret, 0, NULL, NULL);
+
+       /* add pending list to wait app launched successfully */
+       if (pending) {
+               reply = _request_reply_create_full(req, ret, ret,
+                               _request_get_cmd(req), NULL, NULL);
+               if (reply == NULL)
+                       return -1;
+
+               if (_request_reply_append(ret, reply) < 0) {
+                       _request_send_result(req, ret);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int __get_caller_uid(bundle *kb, uid_t *uid)
+{
+       const char *val;
+
+       val = bundle_get_val(kb, AUL_K_ORG_CALLER_UID);
+       if (val == NULL)
+               val = bundle_get_val(kb, AUL_K_CALLER_UID);
+
+       if (val == NULL) {
+               _E("Failed to get caller uid");
+               return -1;
+       }
+
+       *uid = atol(val);
+       _D("caller uid(%d)", *uid);
+
+       return 0;
+}
+
+static void __set_instance_id(bundle *kb)
+{
+       app_status_h app_status;
+       const char *instance_id;
+       const char *callee_pid;
+       int pid;
+
+       callee_pid = bundle_get_val(kb, AUL_K_FWD_CALLEE_PID);
+       if (callee_pid == NULL)
+               callee_pid = bundle_get_val(kb, AUL_K_CALLEE_PID);
+
+       if (callee_pid == NULL) {
+               _E("Failed to get callee pid");
+               return;
+       }
+
+       pid = atoi(callee_pid);
+       if (pid <= 0)
+               return;
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL)
+               return;
+
+       instance_id = _app_status_get_instance_id(app_status);
+       if (instance_id == NULL)
+               return;
+
+       bundle_del(kb, AUL_K_INSTANCE_ID);
+       bundle_add(kb, AUL_K_INSTANCE_ID, instance_id);
+       _D("instance_id(%s)", instance_id);
+}
+
+static int __get_caller_pid(bundle *kb)
+{
+       const char *pid_str;
+       int pid;
+
+       pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
+       if (pid_str)
+               goto end;
+
+       pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
+       if (pid_str == NULL)
+               return -1;
+
+end:
+       pid = atoi(pid_str);
+       if (pid <= 1)
+               return -1;
+
+       return pid;
+}
+
+static int __dispatch_app_result(request_h req)
+{
+       bundle *kb;
+       int pid;
+       int pgid;
+       char tmp_pid[MAX_PID_STR_BUFSZ];
+       int res;
+       const char *appid;
+       uid_t target_uid = _request_get_target_uid(req);
+       app_status_h app_status;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       pid = __get_caller_pid(kb);
+       if (pid < 0)
+               return AUL_R_ERROR;
+
+       pgid = getpgid(_request_get_pid(req));
+       if (pgid > 0) {
+               snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", pgid);
+               bundle_del(kb, AUL_K_CALLEE_PID);
+               bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
+       }
+
+       if (__get_caller_uid(kb, &target_uid) < 0)
+               return AUL_R_ERROR;
+
+       __set_instance_id(kb);
+       app_status = _app_status_find(getpgid(pid));
+       appid = _app_status_get_appid(app_status);
+
+       _noti_send("launch.app_result.start", pgid, target_uid, (void *)appid, kb);
+       res = aul_sock_send_bundle(pid, target_uid, _request_get_cmd(req), kb,
+                       AUL_SOCK_NOREPLY);
+       if (res < 0)
+               res = AUL_R_ERROR;
+
+       _noti_send("launch.app_result.end", pid, target_uid, GINT_TO_POINTER(res), NULL);
+
+       return 0;
+}
+
+static int __dispatch_app_pause(request_h req)
+{
+       const char *appid;
+       bundle *kb;
+       int ret;
+       app_status_h app_status;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       app_status = _app_status_find_by_appid(appid,
+                       _request_get_target_uid(req));
+       ret = _app_status_get_pid(app_status);
+       if (ret > 0)
+               ret = _pause_app(ret, req);
+       else
+               _E("%s is not running", appid);
+
+       return 0;
+}
+
+static int __app_process_by_pid(request_h req, const char *pid_str,
+               bool *pending)
+{
+       int pid;
+       int ret;
+       int dummy;
+       const char *appid;
+       const char *pkgid;
+       const char *type;
+       const struct appinfo *ai;
+       uid_t target_uid = _request_get_target_uid(req);
+       app_status_h app_status;
+
+       if (pid_str == NULL)
+               return -1;
+
+       pid = atoi(pid_str);
+       if (pid <= 1) {
+               _E("invalid pid");
+               return -1;
+       }
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL) {
+               _E("pid %d is not an application", pid);
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       appid = _app_status_get_appid(app_status);
+       ai = _appinfo_find(target_uid, appid);
+       if (ai == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       pkgid = _appinfo_get_value(ai, AIT_PKGID);
+       type = _appinfo_get_value(ai, AIT_COMPTYPE);
+
+       switch (_request_get_cmd(req)) {
+       case APP_RESUME_BY_PID:
+       case APP_RESUME_BY_PID_ASYNC:
+       case APP_PAUSE_BY_PID:
+               aul_send_app_resume_request_signal(pid, appid, pkgid, type);
+               break;
+       default:
+               aul_send_app_terminate_request_signal(pid, appid, pkgid, type);
+               break;
+       }
+
+       switch (_request_get_cmd(req)) {
+       case APP_RESUME_BY_PID_ASYNC:
+               _request_send_result(req, 0);
+       case APP_RESUME_BY_PID:
+               ret = _resume_app(pid, req);
+               break;
+       case APP_TERM_BY_PID:
+       case APP_TERM_BY_PID_WITHOUT_RESTART:
+               ret = _term_app(pid, req);
+               break;
+       case APP_TERM_BGAPP_BY_PID:
+               ret = _term_bgapp(pid, req);
+               break;
+       case APP_KILL_BY_PID:
+               ret = _send_to_sigkill(pid);
+               if (ret < 0)
+                       _E("fail to killing - %d\n", pid);
+               _app_status_update_status(app_status, STATUS_DYING, false, true);
+               _request_send_result(req, ret);
+               break;
+       case APP_TERM_REQ_BY_PID:
+               ret = _term_req_app(pid, req);
+               break;
+       case APP_TERM_BY_PID_ASYNC:
+               ret = aul_sock_send_raw(pid, target_uid, _request_get_cmd(req),
+                               (unsigned char *)&dummy, sizeof(int),
+                               AUL_SOCK_NOREPLY);
+               if (ret < 0)
+                       _D("terminate req packet send error");
+
+               _request_send_result(req, ret);
+               break;
+       case APP_PAUSE_BY_PID:
+               ret = _pause_app(pid, req);
+               break;
+       case APP_TERM_BY_PID_SYNC:
+       case APP_TERM_BY_PID_SYNC_WITHOUT_RESTART:
+               if (_app_status_get_status(app_status) == STATUS_DYING) {
+                       _W("%d is dying", pid);
+                       if (pending)
+                               *pending = true;
+                       ret = 0;
+                       break;
+               }
+               ret = _term_app_v2(pid, req, pending);
+               break;
+       default:
+               _E("unknown command: %d", _request_get_cmd(req));
+               ret = -1;
+       }
+
+       return ret;
+}
+
+static int __dispatch_app_process_by_pid(request_h req)
+{
+       const char *appid;
+       bundle *kb;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       __app_process_by_pid(req, appid, NULL);
+
+       return 0;
+}
+
+static int __dispatch_app_term_async(request_h req)
+{
+       const char *appid;
+       bundle *kb;
+       const char *term_pid;
+       struct appinfo *ai;
+       app_status_h app_status;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       term_pid = bundle_get_val(kb, AUL_K_APPID);
+       app_status = _app_status_find(atoi(term_pid));
+       appid = _app_status_get_appid(app_status);
+       ai = _appinfo_find(_request_get_target_uid(req), appid);
+       if (ai) {
+               _appinfo_set_value(ai, AIT_STATUS, "norestart");
+               __app_process_by_pid(req, term_pid, NULL);
+       }
+
+       return 0;
+}
+
+static int __dispatch_app_term(request_h req)
+{
+       const char *appid;
+       bundle *kb;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       __app_process_by_pid(req, appid, NULL);
+
+       return 0;
+}
+
+static int __dispatch_app_term_sync(request_h req)
+{
+       int ret;
+       int pid;
+       const char *appid;
+       bundle *kb;
+       bool pending = false;
+       request_reply_h reply;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       appid = bundle_get_val(kb, AUL_K_APPID);
+       ret = __app_process_by_pid(req, appid, &pending);
+       if (ret < 0)
+               return -1;
+
+       /* add pending list to wait app terminated successfully */
+       if (pending) {
+               pid = atoi(appid);
+               reply = _request_reply_create_full(req, pid, -EAGAIN,
+                               _request_get_cmd(req), NULL, NULL);
+               if (reply == NULL)
+                       return -1;
+
+               _request_reply_append(pid, reply);
+               _request_reply_reset_pending_timer(req, -1, pid);
+       }
+
+       return 0;
+}
+
+static int __dispatch_app_term_sync_without_restart(request_h req)
+{
+       int ret = -1;
+       const char *appid;
+       const char *term_pid;
+       const char *component_type;
+       struct appinfo *ai;
+       app_status_h app_status;
+
+       term_pid = bundle_get_val(_request_get_bundle(req), AUL_K_APPID);
+       if (term_pid == NULL)
+               goto exception;
+
+       app_status = _app_status_find(atoi(term_pid));
+       if (app_status == NULL)
+               goto exception;
+
+       appid = _app_status_get_appid(app_status);
+       if (appid == NULL)
+               goto exception;
+
+       ai = _appinfo_find(_request_get_target_uid(req), appid);
+       if (ai == NULL)
+               goto exception;
+
+       component_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+       if (!component_type)
+               goto exception;
+
+       ret = __dispatch_app_term_sync(req);
+       if (ret < 0)
+               return ret;
+
+       if (strcmp(component_type, APP_TYPE_SERVICE) == 0)
+               _appinfo_set_value(ai, AIT_STATUS, "norestart");
+       return 0;
+
+exception:
+       _request_send_result(req, ret);
+       return ret;
+}
+
+static int __dispatch_app_startup_signal(request_h req)
+{
+       int pid = _request_get_pid(req);
+       app_status_h app_status;
+
+       _I("[APP_STARTUP_SIGNAL] pid(%d)", pid);
+       app_status = _app_status_find(pid);
+       if (app_status == NULL)
+               return -1;
+
+       _app_status_update_is_starting(app_status, true);
+       if (_app_status_get_app_type(app_status) == AT_UI_APP &&
+                       _app_status_get_status(app_status) != STATUS_VISIBLE)
+               __launch_add_fgmgr(pid);
+
+       _request_reply_reset_pending_timer(req, PENDING_REQUEST_TIMEOUT, pid);
+       _noti_send("launch.app_startup_signal.end", pid, 0, req, NULL);
+
+       return 0;
+}
+
+static const char *__convert_operation_to_privilege(const char *operation)
+{
+       if (operation == NULL)
+               return NULL;
+       else if (!strcmp(operation, AUL_SVC_OPERATION_DOWNLOAD))
+               return PRIVILEGE_DOWNLOAD;
+       else if (!strcmp(operation, AUL_SVC_OPERATION_CALL))
+               return PRIVILEGE_CALL;
+
+       return NULL;
+}
+
+struct checker_info {
+       caller_info_h caller;
+       request_h req;
+       int result;
+};
+
+int __appcontrol_privilege_func(const char *privilege_name,
+               void *user_data)
+{
+       int ret;
+       struct checker_info *info = (struct checker_info *)user_data;
+
+       ret = _cynara_simple_checker(info->caller, info->req,
+                       (void *)privilege_name);
+       if (ret >= 0 && info->result == AMD_CYNARA_UNKNOWN)
+               return ret;
+
+       info->result = ret;
+       return ret;
+}
+
+static int __appcontrol_checker(caller_info_h info, request_h req,
+               void *data)
+{
+       bundle *appcontrol;
+       const char *op_priv = NULL;
+       const char *appid = NULL;
+       char *op = NULL;
+       const char *uri = NULL;
+       const char *mime = NULL;
+       int ret;
+       bool unknown = false;
+       const char *syspopup;
+       const char *below;
+       struct checker_info checker = {
+               .caller = info,
+               .req = req,
+               .result = AMD_CYNARA_ALLOWED
+       };
+
+       appcontrol = _request_get_bundle(req);
+       if (appcontrol == NULL)
+               return AMD_CYNARA_ALLOWED;
+
+       ret = _cynara_sub_checker_check("appcontrol", info, req);
+       if (ret != AMD_CYNARA_CONTINUE)
+               return ret;
+
+       ret = bundle_get_str(appcontrol, AUL_SVC_K_OPERATION, &op);
+       if (ret == BUNDLE_ERROR_NONE)
+               op_priv = __convert_operation_to_privilege(op);
+       if (op_priv) {
+               ret = _cynara_simple_checker(info, req, (void *)op_priv);
+               if (ret < 0)
+                       return ret;
+               if (ret == AMD_CYNARA_UNKNOWN)
+                       unknown = true;
+       }
+
+       appid = bundle_get_val(appcontrol, AUL_K_APPID);
+       if (appid && op) {
+               uri = bundle_get_val(appcontrol, AUL_SVC_K_URI);
+               mime = bundle_get_val(appcontrol, AUL_SVC_K_MIME);
+
+               ret = pkgmgrinfo_appinfo_usr_foreach_appcontrol_privileges(
+                               appid, op, uri, mime,
+                               __appcontrol_privilege_func,
+                               &checker, _request_get_target_uid(req));
+               if (ret < 0) {
+                       _E("Failed to get appcontrol privileges");
+                       return ret;
+               }
+
+               if (checker.result < 0)
+                       return checker.result;
+               else if (checker.result == AMD_CYNARA_UNKNOWN)
+                       unknown = true;
+       }
+
+       syspopup = bundle_get_val(appcontrol, SYSPOPUP_NAME);
+       below = bundle_get_val(appcontrol, AUL_SVC_K_RELOCATE_BELOW);
+       if (below || syspopup) {
+               ret = _cynara_simple_checker(info, req, PRIVILEGE_PLATFORM);
+               if (ret < 0)
+                       return ret;
+               if (ret == AMD_CYNARA_UNKNOWN)
+                       unknown = true;
+       }
+
+       ret = _cynara_simple_checker(info, req, PRIVILEGE_APPMANAGER_LAUNCH);
+       if (unknown && ret >= 0)
+               return AMD_CYNARA_UNKNOWN;
+
+       return ret;
+}
+
+static request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = APP_START,
+               .callback = __dispatch_app_start
+       },
+       {
+               .cmd = APP_START_ASYNC,
+               .callback = __dispatch_app_start
+       },
+       {
+               .cmd = APP_START_RES_ASYNC,
+               .callback = __dispatch_app_start
+       },
+       {
+               .cmd = APP_START_RES,
+               .callback = __dispatch_app_start
+       },
+       {
+               .cmd = APP_OPEN,
+               .callback = __dispatch_app_start
+       },
+       {
+               .cmd = APP_RESUME,
+               .callback = __dispatch_app_start
+       },
+       {
+               .cmd = APP_RESUME_BY_PID,
+               .callback = __dispatch_app_process_by_pid
+       },
+       {
+               .cmd = APP_RESUME_BY_PID_ASYNC,
+               .callback = __dispatch_app_process_by_pid
+       },
+       {
+               .cmd = APP_TERM_BY_PID,
+               .callback = __dispatch_app_term
+       },
+       {
+               .cmd = APP_TERM_BY_PID_WITHOUT_RESTART,
+               .callback = __dispatch_app_term_async
+       },
+       {
+               .cmd = APP_TERM_BY_PID_SYNC,
+               .callback = __dispatch_app_term_sync
+       },
+       {
+               .cmd = APP_TERM_BY_PID_SYNC_WITHOUT_RESTART,
+               .callback = __dispatch_app_term_sync_without_restart
+       },
+       {
+               .cmd = APP_TERM_REQ_BY_PID,
+               .callback = __dispatch_app_process_by_pid
+       },
+       {
+               .cmd = APP_TERM_BY_PID_ASYNC,
+               .callback = __dispatch_app_term_async
+       },
+       {
+               .cmd = APP_TERM_BGAPP_BY_PID,
+               .callback = __dispatch_app_term
+       },
+       {
+               .cmd = APP_RESULT,
+               .callback = __dispatch_app_result
+       },
+       {
+               .cmd = APP_CANCEL,
+               .callback = __dispatch_app_result
+       },
+       {
+               .cmd = APP_PAUSE,
+               .callback = __dispatch_app_pause
+       },
+       {
+               .cmd = APP_PAUSE_BY_PID,
+               .callback = __dispatch_app_process_by_pid
+       },
+       {
+               .cmd = APP_KILL_BY_PID,
+               .callback = __dispatch_app_term
+       },
+       {
+               .cmd = APP_STARTUP_SIGNAL,
+               .callback = __dispatch_app_startup_signal
+       },
+
+};
+
+static cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = APP_OPEN,
+               .checker = __appcontrol_checker,
+               .data = NULL
+       },
+       {
+               .cmd = APP_RESUME,
+               .checker = __appcontrol_checker,
+               .data = NULL
+       },
+       {
+               .cmd = APP_START,
+               .checker = __appcontrol_checker,
+               .data = NULL
+       },
+       {
+               .cmd = APP_START_RES,
+               .checker = __appcontrol_checker,
+               .data = NULL
+       },
+       {
+               .cmd = APP_TERM_BY_PID_WITHOUT_RESTART,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_APPMANAGER_KILL
+       },
+       {
+               .cmd = APP_TERM_BY_PID_ASYNC,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_APPMANAGER_KILL
+       },
+       {
+               .cmd = APP_TERM_BY_PID,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_APPMANAGER_KILL
+       },
+       {
+               .cmd = APP_KILL_BY_PID,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_APPMANAGER_KILL
+       },
+       {
+               .cmd = APP_TERM_BGAPP_BY_PID,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_APPMANAGER_KILL_BGAPP
+       },
+       {
+               .cmd = APP_START_ASYNC,
+               .checker = __appcontrol_checker,
+               .data = NULL
+       },
+       {
+               .cmd = APP_TERM_BY_PID_SYNC,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_APPMANAGER_KILL
+       },
+       {
+               .cmd = APP_TERM_BY_PID_SYNC_WITHOUT_RESTART,
+               .checker = _cynara_simple_checker,
+               .data = PRIVILEGE_APPMANAGER_KILL
+       },
+       {
+               .cmd = APP_START_RES_ASYNC,
+               .checker = __appcontrol_checker,
+               .data = NULL
+       },
+};
+
+static int __on_app_status_cleanup(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       app_status_h app_status = arg3;
+       int pid;
+
+       pid = _app_status_get_pid(app_status);
+       __launch_remove_fgmgr(pid);
+
+       return 0;
+}
+
+static int __default_launcher(bundle *b, uid_t uid, void *data)
+{
+       int r;
+
+       if (!b) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       r = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK, uid,
+                       PAD_CMD_LAUNCH, b);
+       return r;
+}
+
+int _launch_init(void)
+{
+       int ret;
+
+       _D("_launch_init");
+
+       _launchpad_set_launcher(__default_launcher, NULL);
+
+       ret = __listen_app_status_signal(NULL);
+       if (ret < 0)
+               _signal_add_initializer(__listen_app_status_signal, NULL);
+
+       ret = _request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (ret < 0) {
+               _E("Failed to register cmds");
+               return -1;
+       }
+
+       ret = _cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (ret < 0) {
+               _E("Failed to register checkers");
+               return -1;
+       }
+
+       _noti_listen("app_status.cleanup", __on_app_status_cleanup);
+
+       return 0;
+}
+
+static int __check_ver(const char *required, const char *actual)
+{
+       int ret;
+
+       if (required && actual) {
+               ret = strverscmp(required, actual);
+               if (ret < 1)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int __get_prelaunch_attribute(const struct appinfo *ai,
+               const char *appid, uid_t uid)
+{
+       int attribute_val = RESOURCED_BG_MANAGEMENT_ATTRIBUTE;
+       const char *api_version;
+       const char *comp;
+       const char *pkg_type;
+       bool system = false;
+       app_property_h prop;
+       bool activate;
+
+       api_version = _appinfo_get_value(ai, AIT_API_VERSION);
+       if (api_version && __check_ver("2.4", api_version))
+               attribute_val |= RESOURCED_API_VER_2_4_ATTRIBUTE;
+
+       comp = _appinfo_get_value(ai, AIT_COMPTYPE);
+       if (comp && !strcmp(comp, APP_TYPE_SERVICE))
+               attribute_val |= RESOURCED_ATTRIBUTE_SERVICE_APP;
+
+       pkg_type = _appinfo_get_value(ai, AIT_PKGTYPE);
+       if (pkg_type && !strcmp(pkg_type, "wgt")) {
+               attribute_val |= RESOURCED_ATTRIBUTE_LARGEMEMORY;
+               attribute_val |= RESOURCED_ATTRIBUTE_WEB_APP;
+       }
+
+       _appinfo_get_boolean(ai, AIT_SYSTEM, &system);
+       if (!system)
+               attribute_val |= RESOURCED_ATTRIBUTE_DOWNLOAD_APP;
+
+       prop = _app_property_find(uid);
+       if (prop) {
+               activate = _app_property_metadata_query_activation(prop, appid,
+                               METADATA_LARGEMEMORY);
+               if (activate)
+                       attribute_val |= RESOURCED_ATTRIBUTE_LARGEMEMORY;
+               activate = _app_property_metadata_query_activation(prop, appid,
+                               METADATA_OOMTERMINATION);
+               if (activate)
+                       attribute_val |= RESOURCED_ATTRIBUTE_OOMTERMINATION;
+       }
+
+       _D("api-version: %s", api_version);
+       _D("prelaunch attribute %d%d%d%d%d",
+                       (attribute_val & 0x10) >> 4,
+                       (attribute_val & 0x8) >> 3,
+                       (attribute_val & 0x4) >> 2,
+                       (attribute_val & 0x2) >> 1,
+                       (attribute_val & 0x1));
+
+       return attribute_val;
+}
+
+static int __get_background_category(const struct appinfo *ai)
+{
+       int category = 0x0;
+
+       category = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+
+       _D("background category: %#x", category);
+
+       return category;
+}
+
+static void __set_caller_appinfo(const char *caller_appid, int caller_pid,
+               uid_t caller_uid, bundle *kb)
+{
+       char buf[MAX_PID_STR_BUFSZ];
+
+       snprintf(buf, sizeof(buf), "%d", caller_pid);
+       bundle_del(kb, AUL_K_CALLER_PID);
+       bundle_add(kb, AUL_K_CALLER_PID, buf);
+
+       snprintf(buf, sizeof(buf), "%d", caller_uid);
+       bundle_del(kb, AUL_K_CALLER_UID);
+       bundle_add(kb, AUL_K_CALLER_UID, buf);
+
+       if (caller_appid) {
+               bundle_del(kb, AUL_K_CALLER_APPID);
+               bundle_add(kb, AUL_K_CALLER_APPID, caller_appid);
+       }
+}
+
+static const char *__get_caller_appid(int caller_pid, uid_t caller_uid)
+{
+       app_status_h app_status;
+
+       app_status = _app_status_find(caller_pid);
+       if (app_status == NULL && caller_uid >= REGULAR_UID_MIN)
+               app_status = _app_status_find(getpgid(caller_pid));
+
+       return _app_status_get_appid(app_status);
+}
+
+static int __check_executable(const struct appinfo *ai)
+{
+       const char *status;
+       int enable;
+       int ret;
+
+       status = _appinfo_get_value(ai, AIT_STATUS);
+       if (status == NULL)
+               return -1;
+
+       if (strcmp(status, "blocking") == 0) {
+               _D("Blocking");
+               return -EREJECTED;
+       }
+
+       ret = _appinfo_get_int_value(ai, AIT_ENABLEMENT, &enable);
+       if (ret == 0 && !(enable & APP_ENABLEMENT_MASK_ACTIVE)) {
+               _D("Disabled");
+               return -EREJECTED;
+       }
+
+       return 0;
+}
+
+static void __set_appinfo_for_launchpad(const struct appinfo *ai, bundle *kb)
+{
+       const char *str;
+
+       str = _appinfo_get_value(ai, AIT_HWACC);
+       if (str) {
+               bundle_del(kb, AUL_K_HWACC);
+               bundle_add(kb, AUL_K_HWACC, str);
+       }
+
+       str = _appinfo_get_value(ai, AIT_ROOT_PATH);
+       if (str) {
+               bundle_del(kb, AUL_K_ROOT_PATH);
+               bundle_add(kb, AUL_K_ROOT_PATH, str);
+       }
+
+       str = _appinfo_get_value(ai, AIT_EXEC);
+       if (str) {
+               bundle_del(kb, AUL_K_EXEC);
+               bundle_add(kb, AUL_K_EXEC, str);
+       }
+
+       str = _appinfo_get_value(ai, AIT_PKGTYPE);
+       if (str) {
+               bundle_del(kb, AUL_K_PACKAGETYPE);
+               bundle_add(kb, AUL_K_PACKAGETYPE, str);
+       }
+
+       str = _appinfo_get_value(ai, AIT_PKGID);
+       if (str) {
+               bundle_del(kb, AUL_K_PKGID);
+               bundle_add(kb, AUL_K_PKGID, str);
+       }
+
+       str = _appinfo_get_value(ai, AIT_POOL);
+       if (str) {
+               bundle_del(kb, AUL_K_INTERNAL_POOL);
+               bundle_add(kb, AUL_K_INTERNAL_POOL, str);
+       }
+
+       str = _appinfo_get_value(ai, AIT_COMPTYPE);
+       if (str) {
+               bundle_del(kb, AUL_K_COMP_TYPE);
+               bundle_add(kb, AUL_K_COMP_TYPE, str);
+       }
+
+       str = _appinfo_get_value(ai, AIT_APPTYPE);
+       if (str) {
+               bundle_del(kb, AUL_K_APP_TYPE);
+               bundle_add(kb, AUL_K_APP_TYPE, str);
+       }
+
+       str = _appinfo_get_value(ai, AIT_API_VERSION);
+       if (str) {
+               bundle_del(kb, AUL_K_API_VERSION);
+               bundle_add(kb, AUL_K_API_VERSION, str);
+       }
+}
+
+static int __get_app_status(struct launch_s *handle, request_h req,
+               const char *comp_type, const char *caller_appid)
+{
+       const char *widget_viewer;
+       const char *multiple;
+       int *target_pid = NULL;
+       size_t target_pid_sz;
+       bundle *kb = _request_get_bundle(req);
+       int caller_pid = _request_get_pid(req);
+       uid_t target_uid = _request_get_target_uid(req);
+       int ret;
+
+       if (caller_appid && strcmp(comp_type, APP_TYPE_WIDGET) == 0) {
+               handle->is_subapp = true;
+               widget_viewer = bundle_get_val(kb, AUL_K_WIDGET_VIEWER);
+               if (widget_viewer && strcmp(widget_viewer, caller_appid) == 0) {
+                       _D("widget_viewer(%s)", widget_viewer);
+                       handle->app_status = _app_status_find_with_org_caller(
+                                       handle->appid, target_uid, caller_pid);
+               } else {
+                       ret = bundle_get_byte(kb, AUL_K_TARGET_PID,
+                                       (void **)&target_pid, &target_pid_sz);
+                       if (ret != BUNDLE_ERROR_NONE) {
+                               _E("Cannot launch widget app");
+                               return -EREJECTED;
+                       }
+
+                       handle->app_status = _app_status_find(*target_pid);
+                       if (handle->app_status == NULL) {
+                               _E("Cannot find widget app(%d)", *target_pid);
+                               return -EREJECTED;
+                       }
+               }
+       } else if (strcmp(comp_type, APP_TYPE_WATCH) == 0) {
+               handle->is_subapp = true;
+               widget_viewer = bundle_get_val(kb, AUL_K_WIDGET_VIEWER);
+               if (widget_viewer && caller_appid &&
+                               !strcmp(widget_viewer, caller_appid)) {
+                       _D("watch_viewer(%s)", widget_viewer);
+                       handle->app_status = _app_status_find_with_org_caller(
+                                       handle->appid, target_uid, caller_pid);
+               } else {
+                       ret = bundle_get_byte(kb, AUL_K_TARGET_PID,
+                                       (void **)&target_pid, &target_pid_sz);
+                       if (ret != BUNDLE_ERROR_NONE) {
+                               handle->app_status =
+                                       _app_status_find_by_appid_v2(
+                                                       handle->appid,
+                                                       target_uid);
+                       } else {
+                               handle->app_status =
+                                       _app_status_find(*target_pid);
+                       }
+
+                       if (handle->app_status == NULL) {
+                               _E("Cannot find watch app(%s)", handle->appid);
+                               return -EREJECTED;
+                       }
+               }
+       } else {
+               handle->instance_id = bundle_get_val(kb, AUL_K_INSTANCE_ID);
+               if (handle->instance_id) {
+                       handle->app_status = _app_status_find_by_instance_id(
+                                       handle->appid, handle->instance_id,
+                                       target_uid);
+                       if (!handle->app_status && !handle->new_instance) {
+                               _E("Failed to find app instance(%s)",
+                                               handle->instance_id);
+                               return -EREJECTED;
+                       }
+               } else {
+                       multiple = _appinfo_get_value(handle->ai, AIT_MULTI);
+                       if (multiple == NULL || !strcmp(multiple, "false")) {
+                               handle->app_status = _app_status_find_by_appid(
+                                               handle->appid, target_uid);
+                       }
+               }
+       }
+
+       handle->pid = _app_status_get_pid(handle->app_status);
+
+       return 0;
+}
+
+static int __prepare_starting_app(struct launch_s *handle, request_h req,
+               const char *appid, bool new_instance)
+{
+       int ret;
+       int status;
+       const char *pkgid;
+       const char *comp_type;
+       const char *caller_appid;
+       const char *installed_storage;
+       const char *bg_launch;
+       const char *global;
+       int cmd = _request_get_cmd(req);
+       int caller_pid = _request_get_pid(req);
+       uid_t caller_uid = _request_get_uid(req);
+       uid_t target_uid = _request_get_target_uid(req);
+       uid_t pkg_uid;
+       bundle *kb = _request_get_bundle(req);
+       const struct appinfo *caller_ai;
+
+       handle->new_instance = new_instance;
+       handle->appid = appid;
+       handle->ai = _appinfo_find(target_uid, appid);
+       if (handle->ai == NULL) {
+               _D("Failed to find appinfo of %s", appid);
+               return -ENOENT;
+       }
+
+       ret = __check_executable(handle->ai);
+       if (ret < 0)
+               return -1;
+
+       caller_appid = __get_caller_appid(caller_pid, caller_uid);
+       if (caller_appid) {
+               caller_ai = _appinfo_find(caller_uid, caller_appid);
+               if (caller_ai) {
+                       comp_type = _appinfo_get_value(caller_ai, AIT_COMPTYPE);
+                       if (comp_type && !strcmp(comp_type, APP_TYPE_UI))
+                               bundle_del(kb, AUL_SVC_K_CAN_BE_LEADER);
+               }
+       }
+       __set_caller_appinfo(caller_appid, caller_pid, caller_uid, kb);
+
+       ret = __compare_signature(handle->ai, cmd, target_uid, appid,
+                       caller_appid);
+       if (ret < 0)
+               return ret;
+
+       ret = _noti_send("launch.prepare.start", 0, 0,
+                       (void *)(handle->ai), NULL);
+       if (ret < 0) {
+               _E("Unable to launch %s (Some listeners don't want to continue)",
+                               handle->appid);
+               return -1;
+       }
+
+       pkgid = _appinfo_get_value(handle->ai, AIT_PKGID);
+       installed_storage = _appinfo_get_value(handle->ai, AIT_STORAGE_TYPE);
+       if (installed_storage && strcmp(installed_storage, "external") == 0) {
+               global = _appinfo_get_value(handle->ai, AIT_GLOBAL);
+
+               if (global && strcmp("true", global) == 0)
+                       pkg_uid = GLOBAL_USER;
+               else
+                       pkg_uid = target_uid;
+
+               if (app2ext_usr_enable_external_pkg(pkgid, pkg_uid) < 0) {
+                       _E("Failed to enable exteranl pkg(%s)", pkgid);
+                       return -1;
+               }
+       }
+
+       bg_launch = bundle_get_val(kb, AUL_SVC_K_BG_LAUNCH);
+       if (bg_launch && strcmp(bg_launch, "enable") == 0)
+               handle->bg_launch = true;
+
+       comp_type = _appinfo_get_value(handle->ai, AIT_COMPTYPE);
+       if (comp_type == NULL)
+               return -1;
+
+       ret = __get_app_status(handle, req, comp_type, caller_appid);
+       if (ret < 0)
+               return ret;
+
+       if (strcmp(comp_type, APP_TYPE_UI) == 0) {
+               status = _app_status_get_status(handle->app_status);
+               ret = _noti_send("launch.prepare.ui.start", status, target_uid,
+                               handle, kb);
+               if (ret < 0)
+                       return -EILLEGALACCESS;
+
+               if (handle->pid <= 0 || status == STATUS_DYING)
+                       handle->new_process = true;
+
+               if (handle->pid > 0)
+                       handle->app_status = _app_status_find(handle->pid);
+
+               if (_noti_send("launch.prepare.ui.end",
+                               handle->bg_launch, 0,
+                               (void *)(handle->app_status), NULL) < 0)
+                       return -1;
+       } else if (caller_appid && strcmp(comp_type, APP_TYPE_SERVICE) == 0) {
+               ret = __check_execute_permission(pkgid, caller_appid,
+                               target_uid, kb);
+               if (ret < 0)
+                       return ret;
+               if (_noti_send("launch.prepare.service", 0, 0, req, NULL) < 0)
+                       return -1;
+       } else if (caller_appid && strcmp(comp_type, APP_TYPE_WIDGET) == 0) {
+               if (_noti_send("launch.prepare.widget", 0, 0, req, NULL) < 0)
+                       return -1;
+       }
+
+       if (cmd == APP_START_RES) {
+               bundle_del(kb, AUL_K_WAIT_RESULT);
+               bundle_add(kb, AUL_K_WAIT_RESULT, "1");
+       }
+
+       _noti_send("launch.prepare.end", caller_pid, target_uid, (void *)(handle->ai), kb);
+       handle->prelaunch_attr = __get_prelaunch_attribute(
+                       handle->ai, appid, target_uid);
+       handle->bg_category = __get_background_category(handle->ai);
+       handle->bg_allowed = _suspend_is_allowed_background(handle->ai);
+       if (handle->bg_allowed) {
+               _D("[__SUSPEND__] allowed background, appid: %s, app-type: %s",
+                               appid, comp_type);
+               bundle_del(kb, AUL_K_ALLOWED_BG);
+               bundle_add(kb, AUL_K_ALLOWED_BG, "ALLOWED_BG");
+       }
+
+       return 0;
+}
+
+static int __do_starting_app(struct launch_s *handle, request_h req,
+               bool *pending, bool *bg_launch)
+{
+       int status = -1;
+       int cmd = _request_get_cmd(req);
+       int caller_pid = _request_get_pid(req);
+       uid_t target_uid = _request_get_target_uid(req);
+       bundle *kb = _request_get_bundle(req);
+       const char *pkgid;
+       const char *comp_type;
+       int ret;
+       char err_buf[1024];
+       bool socket_exists;
+       bool is_ime = false;
+
+       pkgid = _appinfo_get_value(handle->ai, AIT_PKGID);
+       comp_type = _appinfo_get_value(handle->ai, AIT_COMPTYPE);
+       status = _app_status_get_status(handle->app_status);
+       if (handle->pid > 0 && status != STATUS_DYING) {
+               if (handle->pid == caller_pid) {
+                       SECURE_LOGD("caller & callee process are same. %s:%d,",
+                                       handle->appid, handle->pid);
+                       return -ELOCALLAUNCH_ID;
+               }
+
+               _util_save_log("RESUMING", handle->appid);
+
+               aul_send_app_resume_request_signal(handle->pid,
+                               handle->appid, pkgid, comp_type);
+               _suspend_remove_timer(handle->pid);
+               if (comp_type && !strcmp(comp_type, APP_TYPE_SERVICE)) {
+                       if (handle->bg_allowed == false) {
+                               __prepare_to_wake_services(handle->pid,
+                                               target_uid);
+                       }
+               }
+
+               ret = __nofork_processing(cmd, handle->pid, kb, req);
+               if (ret < 0) {
+                       _noti_send("launch.do_starting_app.relaunch.cancel", ret,
+                                       0, NULL, NULL);
+                       socket_exists =
+                               _app_status_socket_exists(handle->app_status);
+                       if (ret == -ECOMM && socket_exists) {
+                               _E("ECOMM error, we will term the app - %s:%d",
+                                               handle->appid, handle->pid);
+                               _send_to_sigkill(handle->pid);
+                               _app_status_cleanup(handle->app_status);
+                               return -1;
+                       }
+               }
+
+               _app_status_update_last_caller_pid(
+                               handle->app_status, caller_pid);
+               _app_status_update_bg_launch(
+                               handle->app_status, handle->bg_launch);
+               *bg_launch = _app_status_get_bg_launch(handle->app_status);
+
+               return ret;
+       }
+
+       if (handle->pid > 0 && status == STATUS_DYING) {
+               ret = kill(handle->pid, SIGKILL);
+               if (ret == -1) {
+                       _W("Failed to send SIGKILL: %d:%s,", handle->pid,
+                               strerror_r(errno, err_buf, sizeof(err_buf)));
+               }
+               _app_status_cleanup(handle->app_status);
+       }
+
+       __set_appinfo_for_launchpad(handle->ai, kb);
+       if (bundle_get_type(kb, AUL_K_SDK) != BUNDLE_TYPE_NONE) {
+               aul_svc_set_loader_id(kb, PAD_LOADER_ID_DIRECT);
+               handle->debug_mode = true;
+       }
+
+       _noti_send("launch.do_starting_app.start", cmd, 0, handle, kb);
+       _signal_send_proc_prelaunch(handle->appid, pkgid,
+                       handle->prelaunch_attr, handle->bg_category);
+       _signal_send_cpu_boost(APP_BOOSTING_PERIOD);
+
+       ret = _launchpad_launch(kb, target_uid);
+       if (ret < 0) {
+               _signal_send_cpu_boost(APP_BOOSTING_STOP);
+               _noti_send("launch.do_starting_app.cancel", ret, 0, NULL, NULL);
+               return ret;
+       }
+
+       handle->pid = ret;
+       *pending = true;
+       *bg_launch = handle->bg_launch;
+
+       _noti_send("launch.do_starting_app.end", 0, 0, handle, NULL);
+       _suspend_add_proc(handle->pid);
+       aul_send_app_launch_request_signal(handle->pid, handle->appid,
+                       pkgid, comp_type);
+       _appinfo_get_boolean(handle->ai, AIT_IME, &is_ime);
+       if (is_ime)
+               _signal_send_system_service(handle->pid);
+
+       _util_save_log("LAUNCHING", handle->appid);
+       if (handle->debug_mode) {
+               _W("Exclude - %s(%d)", handle->appid, handle->pid);
+               aul_update_freezer_status(handle->pid, "exclude");
+               return ret;
+       }
+
+       if (handle->bg_category == BACKGROUND_CATEGORY_BACKGROUND_NETWORK) {
+               if (!handle->bg_allowed)
+                       aul_update_freezer_status(handle->pid, "include");
+       }
+
+       if (comp_type && !strcmp(comp_type, APP_TYPE_SERVICE)) {
+               if (!handle->bg_allowed)
+                       g_idle_add(__check_service_only, GINT_TO_POINTER(ret));
+       }
+
+       return ret;
+}
+
+static int __complete_starting_app(struct launch_s *handle, request_h req)
+{
+       bundle *kb = _request_get_bundle(req);
+       uid_t target_uid = _request_get_target_uid(req);
+       int caller_pid = _request_get_pid(req);
+       const char *comp_type;
+       char log_status[AUL_PR_NAME];
+
+       _noti_send("launch.complete.start", handle->pid, handle->new_process,
+                       (void *)(handle->ai), kb);
+       comp_type = _appinfo_get_value(handle->ai, AIT_COMPTYPE);
+       if (comp_type && !strcmp(comp_type, APP_TYPE_UI)) {
+               if (handle->new_process) {
+                       __pid_of_last_launched_ui_app = handle->pid;
+               }
+       }
+
+       _app_status_add_app_info(handle->ai, handle->pid, handle->is_subapp,
+                       target_uid, caller_pid, handle->bg_launch,
+                       handle->instance_id, handle->debug_mode);
+
+       _noti_send("launch.complete.end", handle->pid, target_uid, NULL, NULL);
+       snprintf(log_status, sizeof(log_status), "SUCCESS: %d", handle->pid);
+       _util_save_log(log_status, handle->appid);
+       return handle->pid;
+}
+
+static void __handle_onboot(void *user_data, const char *appid,
+               struct appinfo *info)
+{
+       uid_t uid = GPOINTER_TO_UINT(user_data);
+
+       _launch_start_onboot_app_local(uid, appid, info);
+}
+
+static gboolean __load_onboot_apps(gpointer data)
+{
+       uid_t uid = GPOINTER_TO_UINT(data);
+
+       _D("onboot uid(%d)", uid);
+       _appinfo_foreach(uid, __handle_onboot, data);
+       _signal_send_display_unlock_state(SYSTEM_LCD_OFF, SYSTEM_SLEEP_MARGIN);
+
+       return FALSE;
+}
+
+int _launch_start_onboot_apps(uid_t uid)
+{
+       _signal_send_display_lock_state(SYSTEM_LCD_OFF,
+                       SYSTEM_STAY_CUR_STATE, 0);
+       g_idle_add(__load_onboot_apps, GUINT_TO_POINTER(uid));
+
+       return 0;
+}
+
+int _launch_start_app(const char *appid, request_h req, bool *pending,
+               bool *bg_launch, bool new_instance)
+{
+       int ret;
+       struct launch_s launch_data = {0,};
+       int caller_pid = _request_get_pid(req);
+       uid_t caller_uid = _request_get_uid(req);
+       int cmd = _request_get_cmd(req);
+
+       traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "AMD:START_APP");
+       _D("_launch_start_app: appid=%s caller pid=%d uid=%d",
+                       appid, caller_pid, caller_uid);
+
+       ret = __prepare_starting_app(&launch_data, req, appid, new_instance);
+       if (ret < 0) {
+               _request_send_result(req, ret);
+               traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
+               _util_save_log("FAILURE", appid);
+               return -1;
+       }
+
+       ret = __do_starting_app(&launch_data, req, pending, bg_launch);
+       if (ret < 0) {
+               _request_send_result(req, ret);
+               traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
+               _util_save_log("FAILURE", appid);
+               return -1;
+       }
+
+       if (cmd == APP_START_ASYNC || cmd == APP_START_RES_ASYNC)
+               _request_send_result(req, ret);
+
+       ret = __complete_starting_app(&launch_data, req);
+       traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
+       if (ret < 0)
+               _util_save_log("FAILURE", appid);
+
+       return ret;
+}
+
+int _launch_context_get_pid(launch_h h)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return -1;
+
+       return h->pid;
+}
+
+int _launch_context_set_pid(launch_h h, int pid)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return -1;
+
+       h->pid = pid;
+
+       return 0;
+}
+
+const char *_launch_context_get_appid(launch_h h)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return NULL;
+
+       return h->appid;
+}
+
+bool _launch_context_is_new_instance(launch_h h)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return false;
+
+       return h->new_instance;
+}
+
+int _launch_context_set_subapp(launch_h h, bool is_subapp)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return -1;
+
+       h->is_subapp = is_subapp;
+
+       return 0;
+}
+
+int _launch_context_set_app_status(launch_h h, app_status_h status)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return -1;
+
+       h->app_status = status;
+
+       return 0;
+}
+
+const char *_launch_context_get_instance_id(launch_h h)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return NULL;
+
+       return h->instance_id;
+}
+
+bool _launch_context_is_subapp(launch_h h)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return false;
+
+       return h->is_subapp;
+}
+
+bool _launch_context_is_bg_launch(launch_h h)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return false;
+
+       return h->bg_launch;
+}
+
+const struct appinfo *_launch_context_get_appinfo(launch_h h)
+{
+       struct launch_s *context = h;
+
+       if (!context)
+               return NULL;
+
+       return h->ai;
+}
+
diff --git a/src/lib/amd_launchpad.c b/src/lib/amd_launchpad.c
new file mode 100644 (file)
index 0000000..58be1db
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "amd_config.h"
+#include "amd_util.h"
+#include "amd_launchpad.h"
+
+struct launchpad_info {
+       int (*launcher)(bundle *, uid_t t, void *);
+       void *data;
+};
+
+static struct launchpad_info __launchpad;
+
+int _launchpad_set_launcher(int (*callback)(bundle *, uid_t, void *),
+               void *user_data)
+{
+       __launchpad.launcher = callback;
+       __launchpad.data = user_data;
+
+       return 0;
+}
+
+int _launchpad_launch(bundle *kb, uid_t uid)
+{
+       if (!__launchpad.launcher) {
+               _E("Launcher is not prepared");
+               return -1;
+       }
+
+       return __launchpad.launcher(kb, uid, __launchpad.data);
+}
diff --git a/src/lib/amd_login_monitor.c b/src/lib/amd_login_monitor.c
new file mode 100644 (file)
index 0000000..074faa1
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <systemd/sd-login.h>
+#include <tzplatform_config.h>
+#include <bundle_internal.h>
+#include <aul.h>
+#include <aul_sock.h>
+
+#include "amd_util.h"
+#include "amd_login_monitor.h"
+#include "amd_appinfo.h"
+#include "amd_app_property.h"
+#include "amd_app_status.h"
+#include "amd_socket.h"
+#include "amd_request.h"
+#include "amd_launch.h"
+#include "amd_signal.h"
+#include "amd_cynara.h"
+#include "amd_noti.h"
+
+#define PATH_AUL_DAEMONS "/run/aul/daemons"
+#define LOGIN_TIMEOUT_SEC 90
+
+typedef int (*login_cb)(uid_t uid);
+typedef void (*logout_cb)(uid_t uid);
+
+typedef struct login_handler_s {
+       uid_state state;
+       login_cb login;
+} login_handler;
+
+typedef struct logout_handler_s {
+       uid_state state;
+       logout_cb logout;
+} logout_handler;
+
+struct login_monitor_s {
+       sd_login_monitor *m;
+       GIOChannel *io;
+       guint sid;
+};
+
+struct user_s {
+       uid_t uid;
+       uid_state state;
+       guint timer;
+};
+
+static guint sid;
+static struct login_monitor_s *login_monitor;
+static GList *user_list;
+static login_handler login_table[] = {
+       {
+               .state = UID_STATE_OPENING | UID_STATE_ONLINE |
+                       UID_STATE_ACTIVE,
+               .login = _appinfo_load
+       },
+       {
+               .state = UID_STATE_OPENING | UID_STATE_ONLINE |
+                       UID_STATE_ACTIVE,
+               .login = _app_property_load
+       },
+       {
+               .state = UID_STATE_OPENING | UID_STATE_ONLINE |
+                       UID_STATE_ACTIVE,
+               .login = _app_status_usr_init
+       },
+       {
+               .state = UID_STATE_ONLINE | UID_STATE_ACTIVE,
+               .login = _request_usr_init
+       },
+       {
+               .state = UID_STATE_ACTIVE,
+               .login = _launch_start_onboot_apps
+       }
+};
+static logout_handler logout_table[] = {
+       {
+               .state = UID_STATE_OFFLINE,
+               .logout = _appinfo_unload
+       },
+       {
+               .state = UID_STATE_OFFLINE,
+               .logout = _app_property_unload
+       },
+       {
+               .state = UID_STATE_CLOSING | UID_STATE_OFFLINE,
+               .logout = _app_status_usr_fini
+       }
+};
+
+static int __connect_to_launchpad(uid_t uid);
+static void __user_login(struct user_s *user);
+
+static gboolean __login_timout_handler(gpointer data)
+{
+       struct user_s *user = (struct user_s *)data;
+
+       if (user->state == UID_STATE_ACTIVE) {
+               user->timer = 0;
+               return FALSE;
+       }
+
+       user->timer = 0;
+       user->state = UID_STATE_ACTIVE;
+       __user_login(user);
+
+       return FALSE;
+}
+
+static void __user_login(struct user_s *user)
+{
+       unsigned int i;
+
+       if (user->state == UID_STATE_OPENING) {
+               if (__connect_to_launchpad(user->uid) == 0) {
+                       user->state = UID_STATE_ONLINE;
+                       user->timer = g_timeout_add_seconds(
+                                       LOGIN_TIMEOUT_SEC,
+                                       __login_timout_handler,
+                                       user);
+               }
+       }
+
+       _D("user login - uid(%d), state(%d)", user->uid, user->state);
+       for (i = 0; i < ARRAY_SIZE(login_table); i++) {
+               if (login_table[i].state & user->state) {
+                       if (login_table[i].login)
+                               login_table[i].login(user->uid);
+               }
+       }
+
+       _noti_send("login_monitor.login", user->uid, user->state, NULL, NULL);
+}
+
+static void __user_logout(struct user_s *user)
+{
+       unsigned int i;
+
+       _D("user logout - uid(%d), state(%d)", user->uid, user->state);
+       for (i = 0; i < ARRAY_SIZE(logout_table); i++) {
+               if (logout_table[i].state & user->state) {
+                       if (logout_table[i].logout)
+                               logout_table[i].logout(user->uid);
+               }
+       }
+
+       _noti_send("login_monitor.logout", user->uid, user->state, NULL, NULL);
+}
+
+void _login_monitor_set_uid_state(uid_t uid, uid_state state)
+{
+       GList *iter;
+       struct user_s *user;
+
+       if (uid < REGULAR_UID_MIN)
+               return;
+
+       iter = g_list_first(user_list);
+       while (iter) {
+               user = (struct user_s *)iter->data;
+               if (user && user->uid == uid && user->state != state) {
+                       user->state = state;
+                       if (user->state == UID_STATE_ONLINE) {
+                               user->timer = g_timeout_add_seconds(
+                                               LOGIN_TIMEOUT_SEC,
+                                               __login_timout_handler,
+                                               user);
+                               __user_login(user);
+                       } else {
+                               __user_logout(user);
+                       }
+                       break;
+               }
+               iter = g_list_next(iter);
+       }
+}
+
+uid_state _login_monitor_get_uid_state(uid_t uid)
+{
+       GList *iter;
+       uid_state res = UID_STATE_UNKNOWN;
+       struct user_s *user;
+
+       if (uid < REGULAR_UID_MIN)
+               return res;
+
+       iter = g_list_first(user_list);
+       while (iter) {
+               user = (struct user_s *)iter->data;
+               if (user && user->uid == uid) {
+                       res = user->state;
+                       break;
+               }
+               iter = g_list_next(iter);
+       }
+
+       return res;
+}
+
+int _login_monitor_get_uids(uid_t **uids)
+{
+       int r;
+       uid_t *l;
+       GList *iter;
+       unsigned int i = 0;
+       struct user_s *user;
+
+       if (uids == NULL) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (user_list == NULL)
+               return -1;
+
+       r = g_list_length(user_list);
+       if (r == 0)
+               return 0;
+
+       l = calloc(r, sizeof(uid_t));
+       if (l == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       iter = g_list_first(user_list);
+       while (iter) {
+               user = (struct user_s *)iter->data;
+               l[i++] = user->uid;
+               iter = g_list_next(iter);
+       }
+
+       *uids = l;
+
+       return r;
+}
+
+static int __connect_to_launchpad(uid_t uid)
+{
+       int r;
+       bundle *b;
+       char path[PATH_MAX];
+
+       snprintf(path, sizeof(path), "%s/%d/%s",
+                       PATH_AUL_DAEMONS, uid, LAUNCHPAD_PROCESS_POOL_SOCK);
+       if (access(path, F_OK) != 0) {
+               _D("%s doesn't exist", path);
+               return -1;
+       }
+
+       b = bundle_create();
+       if (b == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       r = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK,
+                       uid, PAD_CMD_PING, b);
+       bundle_free(b);
+       if (r != 0) {
+               _E("Failed to connect launchpad - uid(%d), result(%d)", uid, r);
+               return -1;
+       }
+
+       return 0;
+}
+
+static gint __compare_uids(gconstpointer a, gconstpointer b)
+{
+       struct user_s *user = (struct user_s *)a;
+       uid_t cur_uid = GPOINTER_TO_UINT(b);
+
+       if (user == NULL)
+               return -1;
+
+       if (user->uid == cur_uid)
+               return 0;
+
+       return -1;
+}
+
+static void __check_user_state(void)
+{
+       uid_t *uids = NULL;
+       int ret;
+       int i;
+       GList *list;
+       char *state = NULL;
+       struct user_s *user;
+
+       ret = sd_get_uids(&uids);
+       if (ret <= 0) {
+               _W("Failed to get uids - %d", ret);
+               return;
+       }
+
+       for (i = 0; i < ret; i++) {
+               if (uids[i] < REGULAR_UID_MIN)
+                       continue;
+
+               if (sd_uid_get_state(uids[i], &state) < 0)
+                       continue;
+
+               list = g_list_find_custom(user_list,
+                               GUINT_TO_POINTER(uids[i]),
+                               __compare_uids);
+
+               if (strcmp(state, "opening") == 0 ||
+                               strcmp(state, "online") == 0) {
+                       if (list == NULL) {
+                               user = malloc(sizeof(struct user_s));
+                               if (user == NULL) {
+                                       _E("out of memory");
+                                       free(uids);
+                                       return;
+                               }
+                               user->uid = uids[i];
+                               user->state = UID_STATE_OPENING;
+                               user->timer = 0;
+                               user_list = g_list_append(user_list, user);
+                               __user_login(user);
+                       }
+               } else if (strcmp(state, "closing") == 0) {
+                       if (list) {
+                               user = (struct user_s *)list->data;
+                               if (user) {
+                                       user->state = UID_STATE_CLOSING;
+                                       __user_logout(user);
+                               }
+                       }
+               } else if (strcmp(state, "offline") == 0) {
+                       if (list) {
+                               user = (struct user_s *)list->data;
+                               if (user) {
+                                       user_list = g_list_remove(user_list,
+                                                       user);
+                                       user->state = UID_STATE_OFFLINE;
+                                       __user_logout(user);
+                                       if (user->timer)
+                                               g_source_remove(user->timer);
+                                       free(user);
+                               }
+                       }
+               }
+               _D("uid(%d), state(%s)", uids[i], state);
+               free(state);
+               state = NULL;
+       }
+       free(uids);
+}
+
+static gboolean __monitor_login_cb(GIOChannel *io, GIOCondition condition,
+               gpointer data)
+{
+       _D("login monitor");
+       sd_login_monitor_flush(login_monitor->m);
+
+       __check_user_state();
+
+       return TRUE;
+}
+
+static int __init_login_monitor(void)
+{
+       int r;
+       int fd;
+
+       login_monitor = (struct login_monitor_s *)calloc(1,
+                       sizeof(struct login_monitor_s));
+       if (login_monitor == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       r = sd_login_monitor_new("uid", &login_monitor->m);
+       if (r < 0) {
+               _E("Failed to create sd login monitor");
+               return -1;
+       }
+
+       fd = sd_login_monitor_get_fd(login_monitor->m);
+       if (fd < 0) {
+               _E("Failed to get file descriptor");
+               return -1;
+       }
+
+       login_monitor->io = g_io_channel_unix_new(fd);
+       if (login_monitor->io == NULL) {
+               _E("Failed to create GIOChannel");
+               return -1;
+       }
+
+       login_monitor->sid = g_io_add_watch(login_monitor->io,
+                       G_IO_IN | G_IO_HUP, __monitor_login_cb, NULL);
+       if (login_monitor->sid == 0) {
+               _E("Failed to add gio watch");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void __fini_login_monitor(void)
+{
+       if (login_monitor == NULL)
+               return;
+
+       if (login_monitor->sid) {
+               g_source_remove(login_monitor->sid);
+               login_monitor->sid = 0;
+       }
+
+       if (login_monitor->io) {
+               g_io_channel_unref(login_monitor->io);
+               login_monitor->io = NULL;
+       }
+
+       if (login_monitor->m) {
+               sd_login_monitor_unref(login_monitor->m);
+               login_monitor->m = NULL;
+       }
+
+       free(login_monitor);
+       login_monitor = NULL;
+}
+
+static int __on_startup_finished(const char *msg, int arg1, int arg2,
+               void *arg3, bundle *data)
+{
+       uid_t uid = (uid_t)arg1;
+       GList *list;
+       struct user_s *user;
+
+       _D("uid(%d)", uid);
+       if (uid < REGULAR_UID_MIN)
+               return -1;
+
+       list = g_list_find_custom(user_list, GUINT_TO_POINTER(uid),
+                       __compare_uids);
+       if (list == NULL) {
+               user = malloc(sizeof(struct user_s));
+               if (user == NULL) {
+                       _E("out of memory");
+                       return -1;
+               }
+               user->uid = uid;
+               user->timer = 0;
+               user_list = g_list_append(user_list, user);
+       } else {
+               user = (struct user_s *)list->data;
+               if (user == NULL)
+                       return -1;
+       }
+
+       if (user->timer) {
+               g_source_remove(user->timer);
+               user->timer = 0;
+       }
+
+       user->state = UID_STATE_ACTIVE;
+       __user_login(user);
+
+       return 0;
+}
+
+static int __startup_finished_cb(uid_t uid, void *user_data)
+{
+       _noti_send("startup.finished", (int)uid, 0, user_data, NULL);
+
+       return 0;
+}
+
+static int __subscribe_startup_finished(void *data)
+{
+       return _signal_subscribe_startup_finished(__startup_finished_cb, data);
+}
+
+static int __dispatch_app_add_loader(request_h req)
+{
+       bundle *kb;
+       int ret;
+       char tmpbuf[MAX_PID_STR_BUFSZ];
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       snprintf(tmpbuf, sizeof(tmpbuf), "%d", getpgid(_request_get_pid(req)));
+       bundle_add(kb, AUL_K_CALLER_PID, tmpbuf);
+       ret = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK,
+                       _request_get_target_uid(req), PAD_CMD_ADD_LOADER, kb);
+       _request_send_result(req, ret);
+
+       return ret;
+}
+
+static int __dispatch_app_remove_loader(request_h req)
+{
+       bundle *kb;
+       int ret;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL)
+               return -1;
+
+       ret = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK,
+                       _request_get_target_uid(req), PAD_CMD_REMOVE_LOADER,
+                       kb);
+       _request_send_result(req, ret);
+
+       return ret;
+}
+
+static int __dispatch_launchpad_dead_signal(request_h req)
+{
+       uid_t target_uid = _request_get_target_uid(req);
+
+       _D("uid(%d)", target_uid);
+       _login_monitor_set_uid_state(target_uid, UID_STATE_CLOSING);
+       close(_request_remove_fd(req));
+
+       return 0;
+}
+
+static int __dispatch_app_prepare_candidate_process(request_h req)
+{
+       bundle *b = NULL;
+       int ret;
+
+       b = bundle_create();
+       if (b == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       ret = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK,
+                       _request_get_target_uid(req), PAD_CMD_DEMAND, b);
+       bundle_free(b);
+
+       _request_send_result(req, ret);
+       return 0;
+}
+
+static int __dispatch_launchpad_launch_signal(request_h req)
+{
+       uid_t target_uid = _request_get_target_uid(req);
+
+       _D("uid(%d)", target_uid);
+       _login_monitor_set_uid_state(target_uid, UID_STATE_ONLINE);
+       close(_request_remove_fd(req));
+
+       return 0;
+}
+
+static int __label_checker(caller_info_h info, request_h req,
+               void *data)
+{
+       if (strcmp(_cynara_caller_info_get_client(info), "System::Privileged") == 0)
+               return 0;
+
+       return -1;
+}
+
+static request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = APP_ADD_LOADER,
+               .callback = __dispatch_app_add_loader
+       },
+       {
+               .cmd = APP_REMOVE_LOADER,
+               .callback = __dispatch_app_remove_loader
+       },
+       {
+               .cmd = LAUNCHPAD_DEAD_SIGNAL,
+               .callback = __dispatch_launchpad_dead_signal
+       },
+       {
+               .cmd = APP_PREPARE_CANDIDATE_PROCESS,
+               .callback = __dispatch_app_prepare_candidate_process
+       },
+       {
+               .cmd = LAUNCHPAD_LAUNCH_SIGNAL,
+               .callback = __dispatch_launchpad_launch_signal
+       },
+
+};
+
+static cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = LAUNCHPAD_LAUNCH_SIGNAL,
+               .checker = __label_checker,
+               .data = NULL
+       },
+       {
+               .cmd = LAUNCHPAD_DEAD_SIGNAL,
+               .checker = __label_checker,
+               .data = NULL
+       },
+};
+
+static gboolean __login_default_user(gpointer data)
+{
+       struct user_s *user;
+       uid_t uid;
+
+       __check_user_state();
+
+       if (user_list == NULL || g_list_length(user_list) == 0) {
+               uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
+               _D("default user(%d)", uid);
+               user = malloc(sizeof(struct user_s));
+               if (user == NULL) {
+                       _E("out of memory");
+                       return G_SOURCE_CONTINUE;
+               }
+
+               user->uid = uid;
+               user->timer = 0;
+               user->state = UID_STATE_OPENING;
+               user_list = g_list_append(user_list, user);
+               __user_login(user);
+       }
+       sid = 0;
+
+       return G_SOURCE_REMOVE;
+}
+
+int _login_monitor_init(void)
+{
+       int r;
+
+       _D("login monitor init");
+       if (__init_login_monitor()) {
+               _E("Failed to initialize login monitor");
+               __fini_login_monitor();
+               return -1;
+       }
+
+       sid = g_idle_add(__login_default_user, NULL);
+
+       _noti_listen("startup.finished", __on_startup_finished);
+       if (__subscribe_startup_finished(NULL) < 0)
+               _signal_add_initializer(__subscribe_startup_finished, NULL);
+
+       r = _request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               _E("Failed to register cmds");
+               return -1;
+       }
+
+       r = _cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (r < 0) {
+               _E("Failed to register checkers");
+               return -1;
+       }
+
+       return 0;
+}
+
+void _login_monitor_fini(void)
+{
+       _D("login monitor fini");
+
+       if (sid)
+               g_source_remove(sid);
+
+       _signal_unsubscribe_startup_finished();
+
+       if (user_list)
+               g_list_free_full(user_list, free);
+
+       __fini_login_monitor();
+}
diff --git a/src/lib/amd_main.c b/src/lib/amd_main.c
new file mode 100644 (file)
index 0000000..f62e8bb
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <dlfcn.h>
+#include <aul.h>
+#include <glib.h>
+#include <tzplatform_config.h>
+#include <systemd/sd-daemon.h>
+
+#include "amd_util.h"
+#include "amd_appinfo.h"
+#include "amd_app_status.h"
+#include "amd_launch.h"
+#include "amd_request.h"
+#include "amd_cynara.h"
+#include "amd_app_com.h"
+#include "amd_socket.h"
+#include "amd_signal.h"
+#include "amd_suspend.h"
+#include "amd_app_property.h"
+#include "amd_login_monitor.h"
+#include "amd_noti.h"
+#include "amd_api.h"
+#include "amd_inotify.h"
+
+#define AMD_MOD_PATH           "/usr/share/amd/mod"
+#define NAME_AMD_MOD_INIT      "AMD_MOD_INIT"
+#define NAME_AMD_MOD_FINI      "AMD_MOD_FINI"
+
+typedef int (*amd_mod_init_cb)(void);
+typedef void (*amd_mod_fini_cb)(void);
+
+struct restart_info {
+       char *appid;
+       int count;
+       guint timer;
+};
+
+static GHashTable *restart_tbl;
+static GList *so_handles;
+static sigset_t old_mask;
+
+static gboolean __restart_timeout_handler(void *data)
+{
+       struct restart_info *ri = (struct restart_info *)data;
+
+       _D("ri (%p)", ri);
+       _D("appid (%s)", ri->appid);
+
+       g_hash_table_remove(restart_tbl, ri->appid);
+       free(ri->appid);
+       free(ri);
+
+       return FALSE;
+}
+
+static bool __check_restart(const char *appid)
+{
+       struct restart_info *ri = NULL;
+       char err_buf[1024];
+
+       ri = g_hash_table_lookup(restart_tbl, appid);
+       if (!ri) {
+               ri = calloc(1, sizeof(struct restart_info));
+               if (!ri) {
+                       _E("create restart info: %s",
+                               strerror_r(errno, err_buf, sizeof(err_buf)));
+                       return false;
+               }
+               ri->appid = strdup(appid);
+               if (ri->appid == NULL) {
+                       _E("Out of memory");
+                       free(ri);
+                       return false;
+               }
+               ri->count = 1;
+               g_hash_table_insert(restart_tbl, ri->appid, ri);
+
+               _D("ri (%p)", ri);
+               _D("appid (%s)", appid);
+
+               ri->timer = g_timeout_add(10 * 1000, __restart_timeout_handler,
+                               ri);
+       } else {
+               ri->count++;
+               _D("count (%d)", ri->count);
+               if (ri->count > 5) {
+                       g_source_remove(ri->timer);
+                       g_hash_table_remove(restart_tbl, ri->appid);
+                       free(ri->appid);
+                       free(ri);
+                       return false;
+               }
+       }
+       return true;
+}
+
+static bool __can_restart_app(const char *appid, uid_t uid)
+{
+       const char *pkg_status;
+       const char *component_type;
+       struct appinfo *ai;
+       int r;
+       int val = 0;
+       int enable = 1;
+
+       _D("appid: %s", appid);
+       ai = _appinfo_find(uid, appid);
+       if (!ai)
+               return false;
+
+       component_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+       if (!component_type)
+               return false;
+
+       if (strcmp(component_type, APP_TYPE_SERVICE) != 0)
+               return false;
+
+       r = _appinfo_get_int_value(ai, AIT_ENABLEMENT, &enable);
+       if (r == 0 && !(enable & APP_ENABLEMENT_MASK_ACTIVE)) {
+               _D("Disabled");
+               return false;
+       }
+
+       pkg_status = _appinfo_get_value(ai, AIT_STATUS);
+       if (pkg_status && strcmp(pkg_status, "blocking") == 0) {
+               _appinfo_set_value(ai, AIT_STATUS, "restart");
+       } else if (pkg_status && strcmp(pkg_status, "norestart") == 0) {
+               _appinfo_set_value(ai, AIT_STATUS, "installed");
+       } else {
+               r = _appinfo_get_int_value(ai, AIT_RESTART, &val);
+               if (r == 0 && val && __check_restart(appid))
+                       return true;
+       }
+
+       return false;
+}
+
+static int __app_dead_handler(int pid, void *data)
+{
+       bool restart = false;
+       char *appid = NULL;
+       const char *tmp_appid;
+       app_status_h app_status;
+       uid_t uid;
+       char buf[MAX_LOCAL_BUFSZ];
+
+       if (pid <= 0)
+               return 0;
+
+       _D("APP_DEAD_SIGNAL : %d", pid);
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL)
+               return 0;
+
+       uid = _app_status_get_uid(app_status);
+       _noti_send("main.app_dead", pid, uid, app_status, NULL);
+       tmp_appid = _app_status_get_appid(app_status);
+       if (tmp_appid == NULL)
+               return 0;
+
+       restart = __can_restart_app(tmp_appid, uid);
+       if (restart) {
+               appid = strdup(tmp_appid);
+               if (appid == NULL)
+                       _W("Out of memory");
+       }
+
+       _request_flush_pending_request(pid);
+       _app_status_publish_status(pid, STATUS_TERMINATE);
+       _app_status_cleanup(app_status);
+
+       if (restart)
+               _launch_start_app_local(uid, appid);
+       if (appid)
+               free(appid);
+
+       snprintf(buf, sizeof(buf), "%d", pid);
+       _util_save_log("TERMINATED", buf);
+       return 0;
+}
+
+static int __listen_app_dead_signal(void *data)
+{
+       int ret;
+
+       ret = aul_listen_app_dead_signal(__app_dead_handler, data);
+       if (ret < 0)
+               return -1;
+
+       return 0;
+}
+
+static void __ignore_app_dead_signal(void)
+{
+       aul_listen_app_dead_signal(NULL, NULL);
+}
+
+static int __load_modules(const char *path)
+{
+       DIR *dp;
+       struct dirent *dentry = NULL;
+       char buf[PATH_MAX];
+       char *ext;
+       void *handle;
+       amd_mod_init_cb init_cb;
+
+       if (path == NULL)
+               return -1;
+
+       dp = opendir(path);
+       if (dp == NULL)
+               return -1;
+
+       while ((dentry = readdir(dp)) != NULL) {
+               if (dentry->d_name[0] == '.')
+                       continue;
+
+               ext = strrchr(dentry->d_name, '.');
+               if (ext && strcmp(ext, ".so") != 0)
+                       continue;
+               snprintf(buf, sizeof(buf), "%s/%s",
+                               path, dentry->d_name);
+
+               handle = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL);
+               if (!handle) {
+                       _E("Failed to load - %s", dlerror());
+                       continue;
+               }
+
+               init_cb = dlsym(handle, NAME_AMD_MOD_INIT);
+               if (!init_cb) {
+                       _E("Failed to find entry point");
+                       dlclose(handle);
+                       continue;
+               }
+
+               if (init_cb() < 0) {
+                       _E("Failed to init %s", dentry->d_name);
+                       dlclose(handle);
+                       closedir(dp);
+                       return -1;
+               }
+
+               so_handles = g_list_append(so_handles, handle);
+       }
+       closedir(dp);
+
+       return 0;
+}
+
+static void __unload_modules()
+{
+       GList *i = so_handles;
+       amd_mod_fini_cb fini_cb;
+
+       while (i) {
+               fini_cb = dlsym(i->data, NAME_AMD_MOD_FINI);
+               if (fini_cb)
+                       fini_cb();
+               else
+                       _E("Failed to find entry point");
+
+               dlclose(i->data);
+               i = g_list_next(i);
+       }
+
+       g_list_free(so_handles);
+       so_handles = NULL;
+}
+
+static void __block_sigchld(void)
+{
+       sigset_t mask;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGCHLD);
+
+       if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0)
+               _E("Failed to chagne blocked signal");
+}
+
+static void __unblock_sigchld(void)
+{
+       if (sigprocmask(SIG_SETMASK, &old_mask, NULL) < 0)
+               _E("Failed to change blocked signal");
+}
+
+static int __init(void)
+{
+       int r;
+
+       __block_sigchld();
+       _request_init();
+       _noti_init();
+       if (_appinfo_init()) {
+               _E("_appinfo_init failed");
+               return -1;
+       }
+
+       if (__listen_app_dead_signal(NULL) < 0) {
+               _W("aul_listen_app_dead_signal failed");
+               _signal_add_initializer(__listen_app_dead_signal, NULL);
+       }
+
+       restart_tbl = g_hash_table_new(g_str_hash, g_str_equal);
+
+       r = _cynara_init();
+       if (r != 0) {
+               _E("cynara initialize failed.");
+               return -1;
+       }
+
+       _app_status_init();
+       _app_com_broker_init();
+       _launch_init();
+       _suspend_init();
+       _signal_init();
+       _app_property_init();
+       _login_monitor_init();
+       _util_init();
+       _inotify_init();
+
+       if (access(AMD_MOD_PATH, F_OK) == 0) {
+               if (__load_modules(AMD_MOD_PATH) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static void __ready(void)
+{
+       int fd;
+
+       _D("AMD is ready");
+
+       fd = creat("/run/.amd_ready",
+               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+       if (fd != -1)
+               close(fd);
+
+       sd_notify(0, "READY=1");
+}
+
+static void __finish(void)
+{
+       __unload_modules();
+       _inotify_fini();
+       _util_fini();
+       _login_monitor_fini();
+       _app_property_fini();
+       _suspend_fini();
+       _app_com_broker_fini();
+       _app_status_finish();
+       _request_fini();
+       _cynara_finish();
+
+       if (restart_tbl) {
+               g_hash_table_destroy(restart_tbl);
+               restart_tbl = NULL;
+       }
+       __ignore_app_dead_signal();
+
+       _appinfo_fini();
+       _noti_fini();
+       __unblock_sigchld();
+}
+
+EXPORT int main(int argc, char *argv[])
+{
+       GMainLoop *mainloop = NULL;
+
+       if (__init() != 0) {
+               _E("AMD Initialization failed!\n");
+               return -1;
+       }
+
+       __ready();
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+       if (!mainloop) {
+               _E("failed to create glib main loop");
+               return -1;
+       }
+       g_main_loop_run(mainloop);
+
+       __finish();
+
+       return 0;
+}
diff --git a/src/lib/amd_noti.c b/src/lib/amd_noti.c
new file mode 100644 (file)
index 0000000..5f41904
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bundle.h>
+#include <glib.h>
+
+#include "amd_config.h"
+#include "amd_util.h"
+#include "amd_noti.h"
+
+static GList *__listeners;
+
+struct listener_s {
+       char *msg;
+       noti_cb callback;
+};
+
+int _noti_send(const char *msg, int arg1, int arg2, void *arg3, bundle *data)
+{
+       struct listener_s *listener;
+       GList *i = __listeners;
+       int ret;
+
+       if (!msg)
+               return -1;
+
+       while (i) {
+               listener = (struct listener_s *)i->data;
+               if (listener->msg && !strcmp(listener->msg, msg)) {
+                       if (listener->callback) {
+                               ret = listener->callback(msg, arg1, arg2,
+                                               arg3, data);
+                               if (ret != NOTI_CONTINUE)
+                                       return -1;
+                       }
+               }
+
+               i = g_list_next(i);
+       }
+
+       return 0;
+}
+
+int _noti_listen(const char *msg, noti_cb callback)
+{
+       struct listener_s *l;
+
+       l = calloc(1, sizeof(struct listener_s));
+       if (!l) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       l->msg = strdup(msg);
+       if (!l->msg) {
+               _E("Out of memory");
+               free(l);
+               return -1;
+       }
+
+       l->callback = callback;
+
+       __listeners = g_list_append(__listeners, l);
+
+       return 0;
+}
+
+int _noti_init(void)
+{
+       return 0;
+}
+
+static void __free_listener(gpointer data)
+{
+       struct listener_s *listener = data;
+
+       free(listener->msg);
+       free(listener);
+}
+
+void _noti_fini(void)
+{
+       g_list_free_full(__listeners, __free_listener);
+       __listeners = NULL;
+}
diff --git a/src/lib/amd_request.c b/src/lib/amd_request.c
new file mode 100644 (file)
index 0000000..72f99ba
--- /dev/null
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <poll.h>
+#include <ctype.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <aul.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <tzplatform_config.h>
+#include <systemd/sd-login.h>
+#include <aul_sock.h>
+#include <aul_svc.h>
+#include <aul_app_com.h>
+
+#include "amd_config.h"
+#include "amd_util.h"
+#include "amd_request.h"
+#include "amd_app_status.h"
+#include "amd_cynara.h"
+#include "amd_socket.h"
+#include "aul_svc_priv_key.h"
+#include "amd_signal.h"
+#include "amd_login_monitor.h"
+#include "amd_noti.h"
+
+#define PENDING_REQUEST_TIMEOUT 5000 /* msec */
+#define SYSTEM_REQUEST_TIMEOUT 90000 /* msec */
+#define PENDING_MESSAGE_MAX_CNT 100
+
+static int amd_fd;
+static GIOChannel *amd_io;
+static guint amd_wid;
+static GHashTable *pending_table;
+static GHashTable *__dispatch_table;
+
+struct pending_item {
+       int pid;
+       guint timer;
+       GList *pending_list;
+       GList *reply_list;
+};
+
+struct request_s {
+       GTimeVal start;
+       guint timer;
+       int cmd;
+       int clifd;
+       pid_t pid;
+       pid_t t_pid;
+       uid_t uid;
+       uid_t t_uid;
+       bundle *kb;
+       int len;
+       int opt;
+       unsigned char data[1];
+};
+
+struct reply_info {
+       guint timer;
+       pid_t pid;
+       int result;
+       int cmd;
+       int clifd;
+       void *extra;
+       void (*extra_free_cb)(void *data);
+};
+
+static gboolean __timeout_pending_item(gpointer user_data);
+static gboolean __dispatch_request(gpointer data);
+static gboolean __timeout_request(gpointer data);
+
+static void __free_reply_info(gpointer data)
+{
+       struct reply_info *reply = (struct reply_info *)data;
+
+       if (reply == NULL)
+               return;
+
+       if (reply->extra && reply->extra_free_cb)
+               reply->extra_free_cb(reply->extra);
+       if (reply->clifd)
+               close(reply->clifd);
+       if (reply->timer)
+               g_source_remove(reply->timer);
+       free(reply);
+}
+
+static gboolean __timeout_reply(gpointer data)
+{
+       struct reply_info *reply = (struct reply_info *)data;
+
+       if (reply == NULL)
+               return FALSE;
+
+       _request_reply_remove(reply->pid, reply);
+       _send_result_to_client(reply->clifd, reply->result);
+       reply->clifd = 0;
+       reply->timer = 0;
+       __free_reply_info(reply);
+
+       return FALSE;
+}
+
+static struct reply_info *__create_reply_info(guint interval, pid_t pid,
+               int result, int cmd, int clifd, void *extra,
+               void (*extra_free_cb)(void *data))
+{
+       struct reply_info *reply;
+
+       reply = malloc(sizeof(struct reply_info));
+       if (reply == NULL) {
+               _E("Out of memory");
+               return NULL;
+       }
+
+       reply->pid = pid;
+       reply->result = result;
+       reply->cmd = cmd;
+       reply->clifd = clifd;
+       reply->timer = g_timeout_add(interval, __timeout_reply, reply);
+       reply->extra = extra;
+       reply->extra_free_cb = extra_free_cb;
+
+       return reply;
+}
+
+static void __free_request(gpointer data)
+{
+       request_h req = (request_h)data;
+
+       if (req == NULL)
+               return;
+
+       if (req->clifd)
+               close(req->clifd);
+       if (req->timer)
+               g_source_remove(req->timer);
+       if (req->kb)
+               bundle_free(req->kb);
+
+       free(req);
+}
+
+static void __free_pending_item(gpointer user_data)
+{
+       struct pending_item *item = (struct pending_item *)user_data;
+
+       if (item == NULL)
+               return;
+
+       if (item->reply_list)
+               g_list_free_full(item->reply_list, __free_reply_info);
+       if (item->pending_list)
+               g_list_free_full(item->pending_list, __free_request);
+       if (g_main_context_find_source_by_user_data(NULL, item))
+               g_source_remove(item->timer);
+       free(item);
+}
+
+static void __timeout_pending_reply(gpointer data, gpointer user_data)
+{
+       struct reply_info *reply = (struct reply_info *)data;
+
+       if (reply == NULL)
+               return;
+
+       _send_result_to_client(reply->clifd, reply->result);
+       reply->clifd = 0;
+}
+
+static void __timeout_pending_request(gpointer data, gpointer user_data)
+{
+       request_h req = (request_h)data;
+
+       if (req == NULL)
+               return;
+
+       _request_send_result(req, -EAGAIN);
+}
+
+static gboolean __timeout_pending_item(gpointer user_data)
+{
+       struct pending_item *item = (struct pending_item *)user_data;
+
+       if (item == NULL)
+               return FALSE;
+
+       g_list_foreach(item->reply_list, __timeout_pending_reply, NULL);
+       g_list_foreach(item->pending_list, __timeout_pending_request, NULL);
+       g_hash_table_remove(pending_table, GINT_TO_POINTER(item->pid));
+
+       return FALSE;
+}
+
+static void __flush_pending_reply_list(GList **reply_list, bool is_dead)
+{
+       GList *iter;
+       struct reply_info *reply;
+
+       if (reply_list == NULL)
+               return;
+
+       iter = g_list_first(*reply_list);
+       while (iter) {
+               reply = (struct reply_info *)iter->data;
+               iter = g_list_next(iter);
+               if (reply == NULL)
+                       continue;
+
+               if (reply->cmd == APP_TERM_BY_PID_SYNC_WITHOUT_RESTART ||
+                               reply->cmd == APP_TERM_BY_PID_SYNC) {
+                       if (!is_dead)
+                               continue;
+
+                       reply->result = 0;
+               }
+
+               *reply_list = g_list_remove(*reply_list, reply);
+               _send_result_to_client(reply->clifd, reply->result);
+               reply->clifd = 0;
+               __free_reply_info(reply);
+       }
+}
+
+static void __flush_pending_request_list(GList **pending_list)
+{
+       GList *iter;
+       request_h req;
+
+       if (pending_list == NULL)
+               return;
+
+       iter = g_list_first(*pending_list);
+       while (iter) {
+               req = (request_h)iter->data;
+               iter = g_list_next(iter);
+               if (req == NULL)
+                       continue;
+
+               *pending_list = g_list_remove(*pending_list, req);
+               if (req->timer) {
+                       g_source_remove(req->timer);
+                       req->timer = 0;
+               }
+               g_idle_add(__dispatch_request, req);
+       }
+}
+
+int _request_flush_pending_request(int pid)
+{
+       struct pending_item *item;
+
+       item = (struct pending_item *)g_hash_table_lookup(pending_table,
+                       GINT_TO_POINTER(pid));
+       if (item == NULL)
+               return -1;
+
+       __flush_pending_reply_list(&item->reply_list, true);
+       __timeout_pending_item((gpointer)item);
+
+       return 0;
+}
+
+int _request_reply_for_pending_request(int pid)
+{
+       struct pending_item *item;
+
+       _app_status_publish_status(pid, STATUS_LAUNCHING);
+
+       item = (struct pending_item *)g_hash_table_lookup(pending_table,
+                       GINT_TO_POINTER(pid));
+       if (item == NULL)
+               return -1;
+
+       __flush_pending_reply_list(&item->reply_list, false);
+       __flush_pending_request_list(&item->pending_list);
+
+       return 0;
+}
+
+static request_h __get_request(int clifd, app_pkt_t *pkt,
+               struct ucred cr)
+{
+       request_h req;
+       const char *target_uid;
+
+       req = (request_h)malloc(sizeof(struct request_s) + pkt->len);
+       if (req == NULL)
+               return NULL;
+
+       g_get_current_time(&req->start);
+       req->timer = 0;
+       req->clifd = clifd;
+       req->pid = cr.pid;
+       req->t_pid = 0;
+       req->uid = cr.uid;
+       req->cmd = pkt->cmd;
+       req->len = pkt->len;
+       req->opt = pkt->opt;
+       memcpy(req->data, pkt->data, pkt->len + 1);
+
+       if (pkt->opt & AUL_SOCK_BUNDLE) {
+               req->kb = bundle_decode(pkt->data, pkt->len);
+               if (req->kb == NULL) {
+                       free(req);
+                       return NULL;
+               }
+
+               target_uid = bundle_get_val(req->kb, AUL_K_TARGET_UID);
+               if (target_uid && isdigit(target_uid[0]))
+                       req->t_uid = atoi(target_uid);
+               else
+                       req->t_uid = cr.uid;
+       } else {
+               req->kb = NULL;
+               req->t_uid = cr.uid;
+       }
+
+       return req;
+}
+
+static gboolean __timeout_request(gpointer data)
+{
+       request_h req = (request_h)data;
+       struct pending_item *item;
+
+       if (req == NULL)
+               return FALSE;
+
+       item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(req->t_pid));
+       if (item)
+               item->pending_list = g_list_remove(item->pending_list, req);
+
+       if (req->clifd)
+               _request_send_result(req, -EAGAIN);
+       req->timer = 0;
+       __free_request(req);
+
+       return FALSE;
+}
+
+static app_status_h __get_app_status(request_h req, const char *appid)
+{
+       int pid;
+       app_status_h app_status;
+       int status;
+       struct appinfo *ai;
+       const char *comp_type;
+
+       switch (req->cmd) {
+       case APP_RESUME_BY_PID:
+       case APP_TERM_BY_PID:
+       case APP_TERM_BY_PID_WITHOUT_RESTART:
+       case APP_KILL_BY_PID:
+       case APP_TERM_REQ_BY_PID:
+       case APP_TERM_BY_PID_ASYNC:
+       case APP_TERM_BGAPP_BY_PID:
+       case APP_PAUSE_BY_PID:
+       case APP_TERM_BY_PID_SYNC:
+       case APP_TERM_BY_PID_SYNC_WITHOUT_RESTART:
+               /* get pid */
+               pid = atoi(appid);
+               app_status = _app_status_find(pid);
+               break;
+       case APP_START_ASYNC:
+       case APP_START_RES_ASYNC:
+               ai = _appinfo_find(_request_get_target_uid(req), appid);
+               comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+               if (comp_type && (strcmp(comp_type, APP_TYPE_WIDGET) == 0 ||
+                               strcmp(comp_type, APP_TYPE_WATCH) == 0)) {
+                       app_status = _app_status_find_with_org_caller(appid,
+                                       _request_get_target_uid(req),
+                                       _request_get_pid(req));
+               } else {
+                       app_status = _app_status_find_by_appid(appid,
+                                       _request_get_target_uid(req));
+               }
+               break;
+       default:
+               app_status = _app_status_find_by_appid(appid,
+                               _request_get_target_uid(req));
+               break;
+       }
+
+       if (app_status == NULL)
+               return NULL;
+
+       status = _app_status_get_status(app_status);
+       if (status == STATUS_DYING)
+               return NULL;
+
+       return app_status;
+}
+
+static int __check_request(request_h req)
+{
+       int pid;
+       struct pending_item *item;
+       app_status_h app_status;
+       const char *appid;
+
+       if (req->opt & AUL_SOCK_NOREPLY)
+               close(_request_remove_fd(req));
+
+       if ((req->opt & AUL_SOCK_QUEUE) == 0)
+               return 0;
+
+       if (req->kb == NULL)
+               return -1;
+
+       appid = bundle_get_val(req->kb, AUL_K_APPID);
+       if (appid == NULL)
+               return -1;
+
+       app_status = __get_app_status(req, appid);
+       if (app_status == NULL)
+               return 0;
+
+       if (_app_status_socket_exists(app_status))
+               return 0;
+
+       pid = _app_status_get_pid(app_status);
+       item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+       if (item == NULL)
+               return 0;
+
+       if (!_app_status_is_starting(app_status)) {
+               req->t_pid = pid;
+               _W("%s(%d) is waiting to be started.", appid, pid);
+               req->timer = g_timeout_add(PENDING_REQUEST_TIMEOUT,
+                               __timeout_request, req);
+       }
+
+       item->pending_list = g_list_append(item->pending_list, req);
+
+       return 1;
+}
+
+static int __check_target_user(request_h req)
+{
+       int r;
+       uid_t *uids;
+       int i;
+       uid_state state;
+
+       if (req->t_uid >= REGULAR_UID_MIN) {
+               state = _login_monitor_get_uid_state(req->t_uid);
+               if (state == UID_STATE_ONLINE || state == UID_STATE_ACTIVE)
+                       return 0;
+
+               return -1;
+       }
+
+       r = _login_monitor_get_uids(&uids);
+       if (r <= 0)
+               return -1;
+
+       for (i = 0; i < r; i++) {
+               state = _login_monitor_get_uid_state(uids[i]);
+               if (state == UID_STATE_ONLINE || state == UID_STATE_ACTIVE) {
+                       req->t_uid = uids[i];
+                       break;
+               }
+       }
+       free(uids);
+
+       if (req->t_uid < REGULAR_UID_MIN)
+               return -1;
+
+       return 0;
+}
+
+static gboolean __dispatch_request(gpointer data)
+{
+       request_h req = (request_h)data;
+       request_cmd_dispatch *dispatcher;
+
+       if (req == NULL)
+               return FALSE;
+
+       if (req->cmd < 0 || req->cmd >= APP_CMD_MAX) {
+               __free_request(req);
+               return FALSE;
+       }
+
+       dispatcher = g_hash_table_lookup(__dispatch_table,
+                       GINT_TO_POINTER(req->cmd));
+       if (dispatcher) {
+               if (dispatcher->callback(req) != 0)
+                       _E("callback returns FALSE : %d", req->cmd);
+       } else {
+               _E("Invalid request or not supported command");
+       }
+
+       __free_request(req);
+
+       return FALSE;
+}
+
+static guint __get_pending_interval(GTimeVal *start, GTimeVal *end)
+{
+       guint sec;
+       guint usec;
+       guint interval;
+
+       sec = (end->tv_sec - start->tv_sec) * 1000;
+       usec = (end->tv_usec - start->tv_usec) / 1000;
+       interval = sec + usec;
+       if (interval >= PENDING_REQUEST_TIMEOUT)
+               return 0;
+
+       return PENDING_REQUEST_TIMEOUT - interval;
+}
+
+int _request_reply_reset_pending_timer(request_h req, unsigned int interval, int pid)
+{
+       struct pending_item *item;
+       GTimeVal end;
+
+       item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+       if (item == NULL) {
+               _W("pending item doesn't exist - pid(%d)", pid);
+               return -1;
+       }
+
+       if (item->timer)
+               g_source_remove(item->timer);
+
+       if (interval <= 0) {
+               g_get_current_time(&end);
+               interval = __get_pending_interval(_request_get_start_time(req), &end);
+       }
+
+       item->timer = g_timeout_add(interval, __timeout_pending_item, item);
+
+       return 0;
+}
+
+int _request_reply_append(int pid, void *reply)
+{
+       struct pending_item *item;
+
+       item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+       if (item == NULL) {
+               item = calloc(1, sizeof(struct pending_item));
+               if (item == NULL) {
+                       _E("Out of memory");
+                       return -1;
+               }
+               item->pid = pid;
+               g_hash_table_insert(pending_table, GINT_TO_POINTER(pid),
+                               item);
+       } else {
+               if (item->timer) {
+                       g_source_remove(item->timer);
+                       item->timer = 0;
+               }
+       }
+
+       item->reply_list = g_list_append(item->reply_list, reply);
+
+       return 0;
+}
+
+int _request_reply_remove(int pid, void *reply)
+{
+       struct pending_item *item;
+
+       item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+       if (item)
+               item->reply_list = g_list_remove(item->reply_list, reply);
+
+       return 0;
+}
+
+request_reply_h _request_reply_create_full(request_h req, pid_t pid, int result,
+               int cmd, void *extra, void (*extra_free_cb)(void *data))
+{
+       request_reply_h reply;
+       unsigned int interval;
+       GTimeVal end;
+       int clifd = _request_remove_fd(req);
+
+       g_get_current_time(&end);
+       interval = __get_pending_interval(_request_get_start_time(req), &end);
+       reply = __create_reply_info(interval, pid, result, cmd, clifd, extra,
+                       extra_free_cb);
+
+       if (reply == NULL) {
+               _send_result_to_client(clifd, -1);
+               return NULL;
+       }
+
+       return reply;
+}
+
+int _request_reply_foreach_extra(int pid, int (*callback)(void *data))
+{
+       struct pending_item *item;
+       GList *iter;
+       struct reply_info *info;
+
+       item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+       if (!item)
+               return -1;
+
+       iter = item->reply_list;
+       while (iter) {
+               info = iter->data;
+               if (!callback(info->extra))
+                       info->extra = NULL;
+               iter = g_list_next(iter);
+       }
+
+       return 0;
+}
+
+int _request_usr_init(uid_t uid)
+{
+       GList *iter;
+       request_h req;
+       int r;
+       struct pending_item *item;
+
+       _noti_send("request.user_init", uid, 0, NULL, NULL);
+       item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(getpid()));
+       if (item == NULL || item->pending_list == NULL)
+               return 0;
+
+       iter = g_list_first(item->pending_list);
+       while (iter) {
+               req = (request_h)iter->data;
+               iter = g_list_next(iter);
+               if (req == NULL)
+                       continue;
+
+               req->t_pid = 0;
+               if (req->t_uid < REGULAR_UID_MIN)
+                       req->t_uid = uid;
+
+               if (req->t_uid == uid) {
+                       g_source_remove(req->timer);
+                       req->timer = 0;
+                       item->pending_list = g_list_remove(item->pending_list,
+                                       req);
+
+                       r = __check_request(req);
+                       if (r == 0)
+                               g_idle_add(__dispatch_request, (gpointer)req);
+                       else if (r < 0)
+                               __free_request(req);
+               }
+       }
+
+       return 0;
+}
+
+static void __cynara_response_callback(enum amd_cynara_res res, request_h req)
+{
+       int ret;
+
+       if (res == AMD_CYNARA_ALLOWED) {
+               ret = __check_request(req);
+               if (ret < 0) {
+                       _request_send_result(req, ret);
+                       __free_request(req);
+                       return;
+               } else if (ret > 0) {
+                       return;
+               }
+               __dispatch_request((gpointer)req);
+       } else {
+               _E("request has been denied by cynara");
+               ret = -EILLEGALACCESS;
+               _request_send_result(req, ret);
+               __free_request(req);
+       }
+
+       return;
+}
+
+static gboolean __request_handler(GIOChannel *io, GIOCondition cond,
+               gpointer data)
+{
+       int fd = g_io_channel_unix_get_fd(io);
+       app_pkt_t *pkt;
+       int ret;
+       int clifd;
+       struct ucred cr;
+       request_h req;
+       int len;
+       struct pending_item *item;
+
+       pkt = aul_sock_recv_pkt(fd, &clifd, &cr);
+       if (pkt == NULL) {
+               _E("recv error");
+               return TRUE;
+       }
+
+       req = __get_request(clifd, pkt, cr);
+       if (req == NULL) {
+               close(clifd);
+               free(pkt);
+               return TRUE;
+       }
+       free(pkt);
+
+       if (req->uid >= REGULAR_UID_MIN) {
+               if (req->uid != req->t_uid) {
+                       _E("request has been deined - uid(%d), target_uid(%d)",
+                                       req->uid, req->t_uid);
+                       ret = -EILLEGALACCESS;
+                       _request_send_result(req, ret);
+                       __free_request(req);
+                       return TRUE;
+               }
+
+               ret = _cynara_check_privilege(req, __cynara_response_callback);
+               if (ret < 0) {
+                       _E("request has been denied by cynara");
+                       ret = -EILLEGALACCESS;
+                       _request_send_result(req, ret);
+                       __free_request(req);
+                       return TRUE;
+               } else if (ret == AMD_CYNARA_UNKNOWN) {
+                       return TRUE;
+               }
+       } else {
+               ret = __check_target_user(req);
+               if (ret < 0 && (req->cmd == APP_START_ASYNC ||
+                                       req->cmd == APP_START_RES_ASYNC)) {
+                       item = g_hash_table_lookup(pending_table,
+                                       GINT_TO_POINTER(getpid()));
+                       if (item == NULL) {
+                               item = calloc(1, sizeof(struct pending_item));
+                               if (item == NULL) {
+                                       _E("Out of memory");
+                                       _request_send_result(req, ret);
+                                       __free_request(req);
+                                       return TRUE;
+                               }
+                               item->pid = getpid();
+                               g_hash_table_insert(pending_table,
+                                               GINT_TO_POINTER(getpid()),
+                                               item);
+                       }
+
+                       len = g_list_length(item->pending_list);
+                       if (len <= PENDING_MESSAGE_MAX_CNT) {
+                               _D("user not logged");
+                               _request_send_result(req, 0);
+                               req->t_pid = getpid();
+                               req->timer = g_timeout_add(
+                                               SYSTEM_REQUEST_TIMEOUT,
+                                               __timeout_request, req);
+                               item->pending_list = g_list_append(
+                                               item->pending_list, req);
+                               return TRUE;
+                       }
+               }
+       }
+
+       ret = __check_request(req);
+       if (ret < 0) {
+               _request_send_result(req, ret);
+               __free_request(req);
+               return TRUE;
+       } else if (ret > 0) {
+               return TRUE;
+       }
+
+       __dispatch_request((gpointer)req);
+
+       return TRUE;
+}
+
+int _request_get_fd(request_h req)
+{
+       return req->clifd;
+}
+
+int _request_get_pid(request_h req)
+{
+       return req->pid;
+}
+
+pid_t _request_get_target_pid(request_h req)
+{
+       return req->t_pid;
+}
+
+bundle *_request_get_bundle(request_h req)
+{
+       return req->kb;
+}
+
+int _request_get_len(request_h req)
+{
+       return req->len;
+}
+
+unsigned char *_request_get_raw(request_h req)
+{
+       return req->data;
+}
+
+GTimeVal *_request_get_start_time(request_h req)
+{
+       return &req->start;
+}
+
+request_h _request_create_local(int cmd, uid_t uid, int pid, bundle *kb)
+{
+       request_h req;
+
+       req = (request_h)malloc(sizeof(struct request_s));
+       if (req == NULL) {
+               _E("out of memory");
+               return NULL;
+       }
+
+       g_get_current_time(&req->start);
+       req->timer = 0;
+       req->clifd = -1;
+       req->pid = pid;
+       req->t_pid = 0;
+       req->uid = getuid();
+       req->t_uid = uid;
+       req->cmd = cmd;
+       req->len = 0;
+       req->opt = AUL_SOCK_NONE;
+       req->kb = bundle_dup(kb);
+
+       return req;
+}
+
+void _request_free_local(request_h req)
+{
+       if (req == NULL)
+               return;
+
+       if (req->kb)
+               bundle_free(req->kb);
+
+       free(req);
+}
+
+int _request_get_cmd(request_h req)
+{
+       return req->cmd;
+}
+
+int _request_set_cmd(request_h req, int cmd)
+{
+       req->cmd = cmd;
+
+       return 0;
+}
+
+int _request_remove_fd(request_h req)
+{
+       int r = req->clifd;
+
+       req->clifd = 0;
+
+       return r;
+}
+
+uid_t _request_get_target_uid(request_h req)
+{
+       return req->t_uid;
+}
+
+uid_t _request_get_uid(request_h req)
+{
+       return req->uid;
+}
+
+int _request_send_raw(request_h req, int cmd, unsigned char *data, int len)
+{
+       return aul_sock_send_raw_with_fd(_request_remove_fd(req), cmd, data,
+                       len, AUL_SOCK_NOREPLY);
+}
+
+int _request_send_result(request_h req, int res)
+{
+       if (req->clifd && (req->opt & AUL_SOCK_NOREPLY))
+               close(_request_remove_fd(req));
+       else if (req->clifd)
+               _send_result_to_client(_request_remove_fd(req), res);
+
+       return 0;
+}
+
+int _request_register_cmds(const request_cmd_dispatch *cmds, int cnt)
+{
+       int i;
+
+       if (cnt <= 0 || !__dispatch_table || !cmds)
+               return -1;
+
+       for (i = 0; i < cnt; i++) {
+               g_hash_table_insert(__dispatch_table,
+                               GINT_TO_POINTER(cmds[i].cmd),
+                               (gpointer)(&cmds[i]));
+       }
+
+       return 0;
+}
+
+int _request_init(void)
+{
+       _D("request init");
+       pending_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                       NULL, __free_pending_item);
+       if (pending_table == NULL) {
+               _E("Failed to create pending table");
+               _request_fini();
+               return -1;
+       }
+
+       amd_fd = _create_sock_activation();
+       if (amd_fd == -1) {
+               _D("Create server socket without socket activation");
+               amd_fd = _create_server_sock();
+               if (amd_fd == -1) {
+                       _E("Create server socket failed.");
+                       _request_fini();
+                       return -1;
+               }
+       }
+
+       amd_io = g_io_channel_unix_new(amd_fd);
+       if (amd_io == NULL) {
+               _E("Failed to create gio channel");
+               _request_fini();
+               return -1;
+       }
+
+       amd_wid = g_io_add_watch(amd_io, G_IO_IN, __request_handler, NULL);
+       if (amd_wid == 0) {
+               _E("Failed to add gio watch");
+               _request_fini();
+               return -1;
+       }
+
+       __dispatch_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                       NULL, NULL);
+
+       return 0;
+}
+
+void _request_fini(void)
+{
+       _D("request fini");
+       if (amd_wid) {
+               g_source_remove(amd_wid);
+               amd_wid = 0;
+       }
+
+       if (amd_io) {
+               g_io_channel_unref(amd_io);
+               amd_io = NULL;
+       }
+
+       if (amd_fd > 0) {
+               close(amd_fd);
+               amd_fd = 0;
+       }
+
+       if (pending_table) {
+               g_hash_table_destroy(pending_table);
+               pending_table = NULL;
+       }
+
+       if (__dispatch_table) {
+               g_hash_table_destroy(__dispatch_table);
+               __dispatch_table = NULL;
+       }
+}
diff --git a/src/lib/amd_signal.c b/src/lib/amd_signal.c
new file mode 100644 (file)
index 0000000..bbc272c
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <gio/gio.h>
+#include <glib.h>
+
+#include "app_signal.h"
+#include "amd_util.h"
+#include "amd_signal.h"
+#include "amd_noti.h"
+
+#define MAX_LABEL_BUFSZ 1024
+#define SIGNAL_INIT_INTERVAL 3
+
+struct signal_initializer {
+       int (*callback)(void *data);
+       void *data;
+};
+
+static GDBusConnection *system_conn;
+static GList *signal_init_list;
+static guint startup_finished_sid;
+static guint user_session_startup_finished_sid;
+static int (*startup_finished_callback)(uid_t, void *);
+static void *startup_finished_data;
+static uid_t startup_finished_uid;
+static bool system_boot_completed;
+static bool user_boot_completed;
+
+static GDBusConnection *__get_system_conn(void)
+{
+       GError *err = NULL;
+
+       if (system_conn)
+               return system_conn;
+
+       system_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+       if (system_conn == NULL) {
+               _E("g_bus_get_sync() is failed: %s", err->message);
+               g_error_free(err);
+               return NULL;
+       }
+
+       return system_conn;
+}
+
+static int __send_signal(const char *object_path, const char *interface_name,
+               const char *signal_name, GVariant *parameters)
+{
+       GError *err = NULL;
+       GDBusConnection *conn;
+
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       if (g_dbus_connection_emit_signal(conn,
+                                       NULL,
+                                       object_path,
+                                       interface_name,
+                                       signal_name,
+                                       parameters,
+                                       &err) == FALSE) {
+               _E("g_dbus_connection_emit_signal() is failed: %s",
+                                       err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
+               _E("g_dbus_connection_flush_sync() is failed: %s",
+                               err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       return 0;
+}
+
+int _signal_send_watchdog(int pid, int signal_num)
+{
+       int r;
+       GVariant *param;
+
+       if (_noti_send("signal.send_watchdog.start", 0, 0, NULL, NULL) < 0) {
+               _E("Some listeners don't want to continue (pid:%d)", pid);
+               return -1;
+       }
+
+       param = g_variant_new("(ii)", pid, signal_num);
+       if (!param) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       r = __send_signal(RESOURCED_PROC_OBJECT,
+                       RESOURCED_PROC_INTERFACE,
+                       RESOURCED_PROC_WATCHDOG_SIGNAL,
+                       param);
+       if (r < 0) {
+               _E("Failed to send a watchdog signal - pid(%d)", pid);
+               return -1;
+       }
+
+       _W("Send a watchdog signal done - pid(%d)", pid);
+
+       return 0;
+}
+
+int _signal_send_proc_prelaunch(const char *appid, const char *pkgid,
+               int attribute, int category)
+{
+       int r;
+       GVariant *param;
+
+       param = g_variant_new("(ssii)", appid, pkgid, attribute, category);
+       if (!param) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       r = __send_signal(RESOURCED_PROC_OBJECT,
+                       RESOURCED_PROC_INTERFACE,
+                       RESOURCED_PROC_PRELAUNCH_SIGNAL,
+                       param);
+       if (r < 0) {
+               _E("Failed to send a prelaunch signal - appid(%s)", appid);
+               return -1;
+       }
+
+       _W("send a prelaunch signal done: " \
+                       "appid(%s) pkgid(%s) attribute(%x) category(%x)",
+                       appid, pkgid, attribute, category);
+
+       return 0;
+}
+
+int _signal_send_tep_mount(char *mnt_path[], const char *pkgid)
+{
+       GError *err = NULL;
+       GDBusMessage *msg;
+       GDBusConnection *conn;
+       int ret = 0;
+       int rv = 0;
+       struct stat link_buf = {0,};
+       GVariant *param;
+       char buf[MAX_LABEL_BUFSZ];
+
+       if (pkgid == NULL) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       rv = lstat(mnt_path[0], &link_buf);
+       if (rv == 0) {
+               rv = unlink(mnt_path[0]);
+               if (rv)
+                       _E("Unable tp remove link file %s", mnt_path[0]);
+       }
+
+       msg = g_dbus_message_new_method_call(TEP_BUS_NAME,
+                                       TEP_OBJECT_PATH,
+                                       TEP_INTERFACE_NAME,
+                                       TEP_MOUNT_METHOD);
+       if (msg == NULL) {
+               _E("g_dbus_message_new_method_call() is failed.");
+               return -1;
+       }
+
+       snprintf(buf, sizeof(buf), "User::Pkg::%s::RO", pkgid);
+       param = g_variant_new("(sss)", mnt_path[0], mnt_path[1], buf);
+       g_dbus_message_set_body(msg, param);
+
+       if (g_dbus_connection_send_message(conn,
+                                       msg,
+                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+                                       NULL,
+                                       &err) == FALSE) {
+               _E("g_dbus_connection_send_message() is failed: %s",
+                                       err->message);
+               ret = -1;
+       }
+
+       if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
+               _E("g_dbus_connection_flush_sync() is failed: %s",
+                                       err->message);
+               ret = -1;
+       }
+
+       g_object_unref(msg);
+       g_clear_error(&err);
+
+       return ret;
+}
+
+int _signal_send_tep_unmount(const char *mnt_path)
+{
+       GError *err = NULL;
+       GDBusMessage *msg;
+       GDBusConnection *conn;
+
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       msg = g_dbus_message_new_method_call(TEP_BUS_NAME,
+                                       TEP_OBJECT_PATH,
+                                       TEP_INTERFACE_NAME,
+                                       TEP_UNMOUNT_METHOD);
+       if (msg == NULL) {
+               _E("g_dbus_message_new_method_call() is failed.");
+               return -1;
+       }
+
+       g_dbus_message_set_body(msg, g_variant_new("(s)", mnt_path));
+       if (g_dbus_connection_send_message(conn,
+                                       msg,
+                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+                                       NULL,
+                                       &err) == FALSE) {
+               _E("g_dbus_connection_send_message() is failed: %s",
+                                       err->message);
+               g_object_unref(msg);
+               g_clear_error(&err);
+               return -1;
+       }
+
+       g_dbus_connection_flush(conn, NULL, NULL, NULL);
+       g_object_unref(msg);
+       g_clear_error(&err);
+
+       return 0;
+}
+
+int _signal_send_proc_suspend(int pid)
+{
+       GError *err = NULL;
+       GDBusConnection *conn;
+
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       if (g_dbus_connection_emit_signal(conn,
+                                       NULL,
+                                       APPFW_SUSPEND_HINT_PATH,
+                                       APPFW_SUSPEND_HINT_INTERFACE,
+                                       APPFW_SUSPEND_HINT_SIGNAL,
+                                       g_variant_new("(i)", pid),
+                                       &err) == FALSE) {
+               _E("g_dbus_connection_emit_signal() is failed: %s",
+                                       err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
+               _E("g_dbus_connection_flush_sync() is failed: %s",
+                                       err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       _D("[__SUSPEND__] Send suspend hint, pid: %d", pid);
+
+       return 0;
+}
+
+int _signal_get_proc_status(const int pid, int *status, int *focused)
+{
+       GError *err = NULL;
+       GDBusMessage *message;
+       GDBusMessage *reply;
+       GVariant *var;
+       GDBusConnection *conn;
+       int proc_status = -1;
+       int proc_focus = -1;
+
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       message = g_dbus_message_new_method_call(WM_PROC_NAME,
+                                       WM_PROC_PATH,
+                                       WM_PROC_INTERFACE,
+                                       WM_PROC_METHOD);
+       if (message == NULL) {
+               _E("g_bus_message_new_method_call() is failed.");
+               return -1;
+       }
+
+       g_dbus_message_set_body(message, g_variant_new("(i)", pid));
+       reply = g_dbus_connection_send_message_with_reply_sync(conn,
+                                       message,
+                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+                                       -1,
+                                       NULL,
+                                       NULL,
+                                       &err);
+       g_dbus_connection_flush(conn, NULL, NULL, NULL);
+       g_object_unref(message);
+       if (reply == NULL) {
+               _E("Failed to send message with reply sync: %s", err->message);
+               g_clear_error(&err);
+               return -1;
+       }
+
+       var = g_dbus_message_get_body(reply);
+       if (var == NULL) {
+               _E("g_dbus_message_get_body() is failed");
+               g_object_unref(reply);
+               return -1;
+       }
+       g_variant_get(var, "(ii)", &proc_status, &proc_focus);
+
+       g_object_unref(reply);
+
+       if (proc_status == -1 || proc_focus == -1) {
+               _E("Failed to get proc status info");
+               return -1;
+       }
+
+       *status = proc_status;
+       *focused = proc_focus;
+       _D("pid(%d), status(%d), focused(%d)", pid, proc_status, proc_focus);
+
+       return 0;
+}
+
+static void __system_bus_signal_handler(GDBusConnection *connection,
+               const gchar *sender_name, const gchar *object_path,
+               const gchar *interface_name, const char *signal_name,
+               GVariant *parameters, gpointer user_data)
+{
+       guint64 uid = 0;
+
+       _W("[SIGNAL_HANDLER] signal(%s)", signal_name);
+       if (g_strcmp0(signal_name, SD_STARTUP_FINISHED_SIGNAL) == 0) {
+               system_boot_completed = true;
+               _D("[SIGNAL_HANDLER] system boot completed");
+       } else if (g_strcmp0(signal_name,
+                       SD_USER_SESSION_STARTUP_FINISHED_SIGNAL) == 0) {
+               user_boot_completed = true;
+               g_variant_get(parameters, "(t)", &uid);
+               startup_finished_uid = (uid_t)uid;
+               _D("[SIGNAL_HANDLER] user boot completed");
+       }
+
+       if (system_boot_completed && user_boot_completed) {
+               if (startup_finished_callback) {
+                       startup_finished_callback(startup_finished_uid,
+                                       startup_finished_data);
+               }
+
+               user_boot_completed = false;
+       }
+}
+
+static guint __subscribe_system_bus(const char *object_path,
+               const char *interface_name, const char *signal_name)
+{
+       guint sid;
+       GError *err = NULL;
+       GDBusConnection *conn;
+
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return 0;
+
+       sid = g_dbus_connection_signal_subscribe(conn,
+                                               NULL,
+                                               interface_name,
+                                               signal_name,
+                                               object_path,
+                                               NULL,
+                                               G_DBUS_SIGNAL_FLAGS_NONE,
+                                               __system_bus_signal_handler,
+                                               NULL,
+                                               NULL);
+       if (sid == 0)
+               _E("g_bus_connection_signal_subscribe() is failed");
+
+       g_clear_error(&err);
+
+       return sid;
+}
+
+int _signal_subscribe_startup_finished(int (*callback)(uid_t uid, void *data),
+               void *user_data)
+{
+       if (callback == NULL)
+               return -1;
+
+       startup_finished_sid = __subscribe_system_bus(SD_OBJECT_PATH,
+                       SD_MANAGER_INTERFACE,
+                       SD_STARTUP_FINISHED_SIGNAL);
+       if (startup_finished_sid == 0) {
+               _E("Failed to subscribe systemd signal");
+               return -1;
+       }
+
+       user_session_startup_finished_sid = __subscribe_system_bus(
+                       SD_OBJECT_PATH,
+                       SD_MANAGER_INTERFACE,
+                       SD_USER_SESSION_STARTUP_FINISHED_SIGNAL);
+       if (user_session_startup_finished_sid == 0) {
+               _E("Failed to subscribe systemd signal");
+               _signal_unsubscribe_startup_finished();
+               return -1;
+       }
+
+       startup_finished_callback = callback;
+       startup_finished_data = user_data;
+       _D("[SIGNAL] subscribe startup finished");
+
+       return 0;
+}
+
+int _signal_unsubscribe_startup_finished(void)
+{
+       GDBusConnection *conn;
+
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       if (!startup_finished_sid && !user_session_startup_finished_sid)
+               return 0;
+
+       if (startup_finished_sid) {
+               g_dbus_connection_signal_unsubscribe(conn,
+                               startup_finished_sid);
+               startup_finished_sid = 0;
+       }
+
+       if (user_session_startup_finished_sid) {
+               g_dbus_connection_signal_unsubscribe(conn,
+                               user_session_startup_finished_sid);
+               user_session_startup_finished_sid = 0;
+       }
+
+       startup_finished_callback = NULL;
+       startup_finished_data = NULL;
+       _D("[SIGNAL] unsubscribe startup finished");
+
+       return 0;
+}
+
+int _signal_send_cpu_boost(int req)
+{
+       GError *err = NULL;
+       GDBusMessage *msg;
+       GDBusConnection *conn;
+       int res = 0;
+
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       msg = g_dbus_message_new_method_call(PASS_BUS_NAME,
+                                               PASS_PATH_PMQOS,
+                                               PASS_INTERFACE_PMQOS,
+                                               PASS_METHOD_APPLAUNCH);
+       if (msg == NULL) {
+               _E("g_dbus_message_new_method_call() is failed.");
+               return -1;
+       }
+
+       g_dbus_message_set_body(msg, g_variant_new("(i)", req));
+       if (g_dbus_connection_send_message(conn,
+                                       msg,
+                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+                                       NULL,
+                                       &err) == FALSE) {
+               _E("g_dbus_connection_send_message() is failed(%s)",
+                                       err->message);
+               res = -1;
+       }
+
+       g_dbus_connection_flush(conn, NULL, NULL, NULL);
+       g_object_unref(msg);
+       g_clear_error(&err);
+
+       _D("send cpu boost req(%d)", req);
+
+       return res;
+}
+
+int _signal_send_display_lock_state(const char *state, const char *flag,
+               unsigned int timeout)
+{
+       GError *err = NULL;
+       GDBusConnection *conn;
+       GDBusMessage *msg;
+       const char *holdkeyblock_string = "holdkeyblock";
+       int ret = 0;
+
+       _D("Acquring display lock");
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       msg = g_dbus_message_new_method_call(SYSTEM_BUS_NAME,
+                       SYSTEM_PATH_DISPLAY,
+                       SYSTEM_INTERFACE_DISPLAY,
+                       SYSTEM_LOCK_STATE);
+       if (msg == NULL) {
+               _E("g_dbus_message_new_method_call() is failed");
+               return -1;
+       }
+
+       g_dbus_message_set_body(msg, g_variant_new("(sssi)", state,
+                       flag, holdkeyblock_string, timeout));
+       if (!g_dbus_connection_send_message(conn, msg,
+                               G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err)) {
+               _E("Unable to send dbus message for acquring lock as  %s",
+                               err->message);
+               ret = -1;
+       }
+
+       _D("Display lock acquired");
+       g_object_unref(msg);
+       g_dbus_connection_flush_sync(conn, NULL, NULL);
+       g_clear_error(&err);
+       return ret;
+}
+
+int _signal_send_display_unlock_state(const char *state, const char *flag)
+{
+       GError *err = NULL;
+       GDBusConnection *conn;
+       GDBusMessage *msg;
+       int ret = 0;
+
+       _D("releasing display lock");
+       conn = __get_system_conn();
+       if (conn == NULL)
+               return -1;
+
+       msg = g_dbus_message_new_method_call(SYSTEM_BUS_NAME,
+                       SYSTEM_PATH_DISPLAY,
+                       SYSTEM_INTERFACE_DISPLAY,
+                       SYSTEM_UNLOCK_STATE);
+       if (msg == NULL) {
+               _E("g_dbus_message_new_method_call() is failed");
+               return -1;
+       }
+
+       g_dbus_message_set_body(msg, g_variant_new("(ss)", state, flag));
+       if (!g_dbus_connection_send_message(conn, msg,
+                               G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err)) {
+               _E("Unable to send dbus message for releasing lock as  %s",
+                       err->message);
+               ret = -1;
+       }
+
+       _D("Display lock released");
+       g_object_unref(msg);
+       g_dbus_connection_flush_sync(conn, NULL, NULL);
+       g_clear_error(&err);
+       return ret;
+}
+
+int _signal_send_system_service(int pid)
+{
+       int r;
+       GVariant *param;
+
+       param = g_variant_new("(i)", pid);
+       if (!param) {
+               _E("Out of memory");
+               return -1;
+       }
+
+       r = __send_signal(RESOURCED_PROC_OBJECT,
+                       RESOURCED_PROC_INTERFACE,
+                       RESOURCED_SYSTEM_SERVICE_SIGNAL,
+                       param);
+       if (r < 0) {
+               _E("Failed to send system service signal - pid(%d)", pid);
+               return -1;
+       }
+
+       _D("Send system service signal: pid(%d)", pid);
+
+       return 0;
+}
+
+int _signal_add_initializer(int (*callback)(void *data), void *user_data)
+{
+       struct signal_initializer *initializer;
+
+       if (callback == NULL) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       initializer = (struct signal_initializer *)malloc(
+                       sizeof(struct signal_initializer));
+       if (initializer == NULL) {
+               _E("out of memory");
+               return -1;
+       }
+
+       initializer->callback = callback;
+       initializer->data = user_data;
+
+       signal_init_list = g_list_append(signal_init_list, initializer);
+
+       return 0;
+}
+
+static gboolean __dispatch_initializer_list(gpointer user_data)
+{
+       struct signal_initializer *initializer;
+       GList *list;
+       int ret;
+
+       list = g_list_first(signal_init_list);
+       while (list) {
+               initializer = (struct signal_initializer *)list->data;
+               list = g_list_next(list);
+               if (initializer) {
+                       ret = initializer->callback(initializer->data);
+                       if (ret == 0) {
+                               signal_init_list =
+                                       g_list_remove(signal_init_list,
+                                                       initializer);
+                               free(initializer);
+                       }
+               }
+       }
+
+       if (signal_init_list == NULL) {
+               _D("init list is NULL");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+int _signal_init(void)
+{
+       if (signal_init_list) {
+               g_timeout_add_seconds(SIGNAL_INIT_INTERVAL,
+                               __dispatch_initializer_list, NULL);
+       }
+
+       return 0;
+}
diff --git a/src/lib/amd_socket.c b/src/lib/amd_socket.c
new file mode 100644 (file)
index 0000000..3aa953c
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <systemd/sd-daemon.h>
+#include <bundle.h>
+#include <aul_sock.h>
+
+#include "amd_util.h"
+#include "amd_socket.h"
+
+#define PATH_AMD_SOCK "/run/aul/daemons/.amd-sock"
+
+int _create_sock_activation(void)
+{
+       int fds;
+
+       fds = sd_listen_fds(0);
+       if (fds == 1) {
+               if (chmod(PATH_AMD_SOCK, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
+                       _E("change mode error: %d", errno);
+               return SD_LISTEN_FDS_START;
+       }
+
+       if (fds > 1)
+               _E("Too many file descriptors received.\n");
+       else
+               _D("There is no socket stream");
+
+       return -1;
+}
+
+int _create_server_sock(void)
+{
+       int fd;
+       struct sockaddr_un addr;
+
+       fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (fd < 0) {
+               _E("create socket error: %d", errno);
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", PATH_AMD_SOCK);
+       unlink(addr.sun_path);
+
+       if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
+               _E("bind error: %d", errno);
+               close(fd);
+               return -1;
+       }
+
+       if (chmod(addr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
+               _E("change mode error: %d", errno);
+               close(fd);
+               return -1;
+       }
+
+       aul_sock_set_sock_option(fd, 0);
+
+       if (listen(fd, 128) == -1) {
+               _E("listen error: %d", errno);
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static int __connect_client_sock(int fd, const struct sockaddr *saptr,
+               socklen_t salen, int nsec)
+{
+       int flags;
+       int ret;
+       int error = 0;
+       socklen_t len;
+       fd_set readfds;
+       fd_set writefds;
+       struct timeval timeout;
+
+       flags = fcntl(fd, F_GETFL, 0);
+       fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+       ret = connect(fd, (struct sockaddr *)saptr, salen);
+       if (ret < 0) {
+               if (errno != EAGAIN && errno != EINPROGRESS) {
+                       fcntl(fd, F_SETFL, flags);
+                       return -2;
+               }
+       }
+
+       /* Do whatever we want while the connect is taking place. */
+       if (ret == 0)
+               goto done;      /* connect completed immediately */
+
+       FD_ZERO(&readfds);
+       FD_SET(fd, &readfds);
+       writefds = readfds;
+       timeout.tv_sec = 0;
+       timeout.tv_usec = nsec;
+
+       ret = select(fd + 1, &readfds, &writefds, NULL,
+                    nsec ? &timeout : NULL);
+       if (ret == 0) {
+               close(fd);      /* timeout */
+               errno = ETIMEDOUT;
+               return -1;
+       }
+
+       if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
+               len = sizeof(error);
+               if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+                       return -1;      /* Solaris pending error */
+       } else {
+               return -1;      /* select error: sockfd not set*/
+       }
+
+done:
+       (void)fcntl(fd, F_SETFL, flags);
+       if (error) {
+               close(fd);
+               errno = error;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __create_launchpad_client_sock(const char *pad_type, uid_t uid)
+{
+       int fd = -1;
+       struct sockaddr_un saddr = { 0, };
+       int retry = 1;
+       int ret = -1;
+
+       fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       /*  support above version 2.6.27*/
+       if (fd < 0) {
+               if (errno == EINVAL) {
+                       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+                       if (fd < 0) {
+                               _E("second chance - socket create error");
+                               return -1;
+                       }
+               } else {
+                       _E("socket error");
+                       return -1;
+               }
+       }
+
+       saddr.sun_family = AF_UNIX;
+       snprintf(saddr.sun_path, sizeof(saddr.sun_path),
+                       "/run/aul/daemons/%d/%s", uid, pad_type);
+ retry_con:
+       ret = __connect_client_sock(fd, (struct sockaddr *)&saddr,
+                       sizeof(saddr), 100 * 1000);
+       if (ret < -1) {
+               _E("maybe peer not launched or peer daed\n");
+               if (retry > 0) {
+                       usleep(100 * 1000);
+                       retry--;
+                       goto retry_con;
+               }
+       }
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+
+       aul_sock_set_sock_option(fd, 1);
+
+       return fd;
+}
+
+int _send_cmd_to_launchpad(const char *pad_type, uid_t uid, int cmd, bundle *kb)
+{
+       int fd;
+       int len;
+       int res;
+       char err_buf[1024];
+
+       fd = __create_launchpad_client_sock(pad_type, uid);
+       if (fd < 0)
+               return -1;
+
+       res = aul_sock_send_bundle_with_fd(fd, cmd, kb, AUL_SOCK_ASYNC);
+       if (res < 0) {
+               close(fd);
+               return res;
+       }
+
+retry_recv:
+       len = recv(fd, &res, sizeof(int), 0);
+       if (len == -1) {
+               if (errno == EAGAIN) {
+                       _E("recv timeout : %s",
+                               strerror_r(errno, err_buf, sizeof(err_buf)));
+                       res = -EAGAIN;
+               } else if (errno == EINTR) {
+                       _D("recv : %s",
+                               strerror_r(errno, err_buf, sizeof(err_buf)));
+                       goto retry_recv;
+               } else {
+                       _E("recv error : %s",
+                               strerror_r(errno, err_buf, sizeof(err_buf)));
+                       res = -ECOMM;
+               }
+       }
+
+       close(fd);
+
+       return res;
+}
+
+void _send_result_to_client(int fd, int res)
+{
+       if (fd < 3)
+               return;
+
+       if (send(fd, &res, sizeof(int), MSG_NOSIGNAL) < 0) {
+               if (errno == EPIPE)
+                       _E("send failed due to EPIPE.");
+               _E("send fail to client");
+       }
+
+       close(fd);
+}
+
+void _send_result_to_client_v2(int fd, int res)
+{
+       if (fd < 3)
+               return;
+
+       if (send(fd, &res, sizeof(int), MSG_NOSIGNAL) < 0) {
+               if (errno == EPIPE)
+                       _E("send failed due to EPIPE.");
+               _E("send fail to client");
+       }
+}
diff --git a/src/lib/amd_suspend.c b/src/lib/amd_suspend.c
new file mode 100644 (file)
index 0000000..791be10
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <bundle_internal.h>
+#include <aul.h>
+#include <aul_sock.h>
+#include <net_connection.h>
+
+#include "amd_config.h"
+#include "amd_signal.h"
+#include "amd_util.h"
+#include "amd_suspend.h"
+#include "amd_app_status.h"
+
+typedef struct proc_info {
+       pid_t pid;
+       guint timer_id;
+} proc_info_t;
+
+static GHashTable *proc_info_tbl;
+static connection_h connection;
+static int network_disconnected;
+
+static void __destroy_proc_info_value(gpointer data)
+{
+       proc_info_t *proc = (proc_info_t *)data;
+
+       if (proc)
+               free(proc);
+}
+
+static int __network_is_disconnected(connection_type_e type)
+{
+       int ret = 0;
+
+       switch (type) {
+       case CONNECTION_TYPE_DISCONNECTED:
+               _D("Disconnected");
+               ret = 1;
+               break;
+       case CONNECTION_TYPE_WIFI:
+               _D("Wi-Fi type");
+               break;
+       case CONNECTION_TYPE_CELLULAR:
+               _D("Cellular type");
+               break;
+       case CONNECTION_TYPE_ETHERNET:
+               _D("Ethernet type");
+               break;
+       case CONNECTION_TYPE_BT:
+               _D("Bluetooth type");
+               break;
+       case CONNECTION_TYPE_NET_PROXY:
+               _D("Proxy type for internet connection");
+               break;
+       default:
+               _E("Unknwon type");
+               break;
+       }
+
+       return ret;
+}
+
+static void __prepare_to_suspend(int pid, uid_t uid)
+{
+       int ret;
+       int dummy = 0;
+
+       _D("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+       ret = aul_sock_send_raw(pid, uid, APP_SUSPEND, (unsigned char *)&dummy,
+                       sizeof(int), AUL_SOCK_NOREPLY);
+       if (ret < 0)
+               _E("Failed to send APP_SUSPEND %d", pid);
+}
+
+static void __prepare_to_wake(int pid, uid_t uid)
+{
+       int ret;
+       bundle *kb;
+
+       kb = bundle_create();
+       if (kb == NULL) {
+               _E("out of memory");
+               return;
+       }
+
+       bundle_add(kb, AUL_K_ALLOWED_BG, "ALLOWED_BG");
+
+       _D("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+       ret = aul_sock_send_bundle(pid, uid, APP_WAKE, kb, AUL_SOCK_NOREPLY);
+       if (ret != AUL_R_OK)
+               _E("Failed to send APP_WAKE %d", pid);
+
+       bundle_free(kb);
+}
+
+static void __wake_bg_apps(app_status_h app_status, void *data)
+{
+       const char *appid;
+       int status;
+       uid_t uid;
+       const struct appinfo *ai;
+       int target_category;
+       int bg_category;
+       bool bg_allowed;
+       int pid;
+
+       if (app_status == NULL)
+               return;
+
+       status = _app_status_get_status(app_status);
+       if (status != STATUS_BG && status != STATUS_SERVICE)
+               return;
+
+       appid = _app_status_get_appid(app_status);
+       uid = _app_status_get_uid(app_status);
+       pid = _app_status_get_pid(app_status);
+
+       ai = _appinfo_find(uid, appid);
+       if (ai == NULL)
+               return;
+
+       if (data) {
+               target_category = GPOINTER_TO_INT(data);
+               bg_category = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+               if (bg_category != target_category)
+                       return;
+       } else {
+               bg_allowed = _suspend_is_allowed_background(ai);
+               if (bg_allowed == true)
+                       return;
+       }
+
+       _D("[__SUSPEND__] Wake %s %d", appid, pid);
+       _suspend_remove_timer(pid);
+       __prepare_to_wake(pid, uid);
+       _app_status_find_service_apps(app_status, status,
+                       __prepare_to_wake, false);
+       aul_update_freezer_status(pid, "exclude");
+}
+
+static void __suspend_bg_apps(app_status_h app_status, void *data)
+{
+       const char *appid;
+       int status;
+       uid_t uid;
+       const struct appinfo *ai;
+       int target_category;
+       int bg_category;
+       bool bg_allowed;
+       int pid;
+
+       if (app_status == NULL)
+               return;
+
+       status = _app_status_get_status(app_status);
+       if (status != STATUS_BG && status != STATUS_SERVICE)
+               return;
+
+       appid = _app_status_get_appid(app_status);
+       uid = _app_status_get_uid(app_status);
+       pid = _app_status_get_pid(app_status);
+
+       ai = _appinfo_find(uid, appid);
+       if (ai == NULL)
+               return;
+
+       if (data) {
+               target_category = GPOINTER_TO_INT(data);
+               bg_category = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+               if (bg_category != target_category)
+                       return;
+       } else {
+               bg_allowed = _suspend_is_allowed_background(ai);
+               if (bg_allowed == true)
+                       return;
+       }
+
+       _D("[__SUSPEND__] Suspend %s %d", appid, pid);
+       _app_status_find_service_apps(app_status, status,
+                       __prepare_to_suspend, true);
+       __prepare_to_suspend(pid, uid);
+       _suspend_add_timer(pid);
+       aul_update_freezer_status(pid, "include");
+}
+
+static void __connection_type_changed_cb(connection_type_e type,
+               void *user_data)
+{
+       int bg_category = BACKGROUND_CATEGORY_BACKGROUND_NETWORK;
+
+       network_disconnected = __network_is_disconnected(type);
+       if (network_disconnected) {
+               _app_status_foreach_running_appinfo(__suspend_bg_apps,
+                               GINT_TO_POINTER(bg_category));
+       } else {
+               _app_status_foreach_running_appinfo(__wake_bg_apps,
+                               GINT_TO_POINTER(bg_category));
+       }
+}
+
+void _suspend_init(void)
+{
+       int ret;
+       connection_type_e type = CONNECTION_TYPE_DISCONNECTED;
+
+       if (!proc_info_tbl) {
+               proc_info_tbl = g_hash_table_new_full(g_direct_hash,
+                               g_direct_equal, NULL,
+                               __destroy_proc_info_value);
+       }
+
+       ret = connection_create(&connection);
+       if (ret != CONNECTION_ERROR_NONE) {
+               _E("Failed to create the connection handle");
+               return;
+       }
+
+       ret = connection_get_type(connection, &type);
+       if (ret == CONNECTION_ERROR_NONE)
+               network_disconnected = __network_is_disconnected(type);
+       else
+               _E("Failed to get the type of the current profile");
+
+       ret = connection_set_type_changed_cb(connection,
+                       __connection_type_changed_cb, NULL);
+       if (ret != CONNECTION_ERROR_NONE) {
+               _E("Failed to register the connection changed callback");
+               connection_destroy(connection);
+               connection = NULL;
+               return;
+       }
+
+       _D("_amd_proc_init done");
+}
+
+void _suspend_fini(void)
+{
+       int ret;
+
+       ret = connection_unset_type_changed_cb(connection);
+       if (ret != CONNECTION_ERROR_NONE)
+               _E("Failed to unregister the connection changed callback");
+
+       ret = connection_destroy(connection);
+       if (ret != CONNECTION_ERROR_NONE)
+               _E("Failed to destroy the connection handle");
+
+       g_hash_table_destroy(proc_info_tbl);
+       _D("_amd_proc_fini done");
+}
+
+proc_info_t *__create_proc_info(int pid)
+{
+       proc_info_t *proc;
+
+       if (pid < 1) {
+               _E("invalid pid");
+               return NULL;
+       }
+
+       proc = (proc_info_t *)malloc(sizeof(proc_info_t));
+       if (proc == NULL) {
+               _E("insufficient memory");
+               return NULL;
+       }
+
+       proc->pid = pid;
+       proc->timer_id = 0;
+
+       return proc;
+}
+
+proc_info_t *__find_proc_info(int pid)
+{
+       proc_info_t *proc;
+
+       if (pid < 1) {
+               _E("invalid pid");
+               return NULL;
+       }
+
+       proc = (proc_info_t *)g_hash_table_lookup(proc_info_tbl,
+                       GINT_TO_POINTER(pid));
+       if (proc == NULL) {
+               _E("proc info not found");
+               return NULL;
+       }
+
+       return proc;
+}
+
+int __add_proc_info(proc_info_t *proc)
+{
+       if (proc == NULL) {
+               _E("invalid proc info");
+               return -1;
+       }
+
+       if (proc->pid < 1) {
+               _E("invalid pid");
+               return -1;
+       }
+
+       g_hash_table_insert(proc_info_tbl, GINT_TO_POINTER(proc->pid), proc);
+
+       return 0;
+}
+
+int _suspend_add_proc(int pid)
+{
+       proc_info_t *proc;
+
+       proc = __create_proc_info(pid);
+       if (proc)
+               return __add_proc_info(proc);
+
+       return -1;
+}
+
+int _suspend_remove_proc(int pid)
+{
+       proc_info_t *proc;
+
+       if (pid < 1) {
+               _E("invalid pid");
+               return -1;
+       }
+
+       proc = (proc_info_t *)g_hash_table_lookup(proc_info_tbl,
+                       GINT_TO_POINTER(pid));
+       if (proc == NULL) {
+               _E("proc info not found");
+               return -1;
+       }
+
+       g_hash_table_remove(proc_info_tbl, GINT_TO_POINTER(pid));
+
+       return 0;
+}
+
+static gboolean __send_suspend_hint(gpointer data)
+{
+       proc_info_t *proc;
+       int pid = GPOINTER_TO_INT(data);
+
+       proc = __find_proc_info(pid);
+       if (proc && proc->timer_id > 0) {
+               _signal_send_proc_suspend(pid);
+               proc->timer_id = 0;
+       }
+
+       return FALSE;
+}
+
+bool _suspend_is_allowed_background(const struct appinfo *ai)
+{
+       int bg_category;
+       const char *comp_type;
+
+       comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+       if (comp_type == NULL)
+               return false;
+
+       if (strcmp(comp_type, APP_TYPE_UI) &&
+                       strcmp(comp_type, APP_TYPE_SERVICE))
+               return true;
+
+       /*
+        * 2.4 bg-categorized (uiapp || svcapp) || watch || widget -> bg allowed
+        * 2.3 uiapp -> not allowed, 2.3 svcapp -> bg allowed
+        */
+       bg_category = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+       if (bg_category) {
+               if (network_disconnected) {
+                       if (bg_category &
+                               (~(int)BACKGROUND_CATEGORY_BACKGROUND_NETWORK))
+                               return true;
+               } else {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+void _suspend_add_timer(int pid)
+{
+       proc_info_t *proc;
+
+       proc = __find_proc_info(pid);
+       if (proc == NULL) {
+               proc = __create_proc_info(pid);
+               if (proc)
+                       __add_proc_info(proc);
+       }
+
+       if (proc) {
+               proc->timer_id = g_timeout_add_seconds(10, __send_suspend_hint,
+                               GINT_TO_POINTER(pid));
+       }
+}
+
+void _suspend_remove_timer(int pid)
+{
+       proc_info_t *proc;
+
+       proc = __find_proc_info(pid);
+       if (proc && proc->timer_id > 0) {
+               g_source_remove(proc->timer_id);
+               proc->timer_id = 0;
+       }
+}
+
+int _suspend_update_status(int pid, int status)
+{
+       app_status_h app_status;
+
+       if (pid < 0)
+               return -1;
+
+       app_status = _app_status_find(pid);
+       if (app_status == NULL)
+               return -1;
+
+       if (status == SUSPEND_STATUS_EXCLUDE) {
+               __wake_bg_apps(app_status, NULL);
+       } else if (status == SUSPEND_STATUS_INCLUDE) {
+               __suspend_bg_apps(app_status, NULL);
+       } else {
+               _E("Unknown status(%d)", status);
+               return -1;
+       }
+       _D("[__SUSPEND__] pid(%d), status(%d)", pid, status);
+
+       return 0;
+}
diff --git a/src/lib/amd_util.c b/src/lib/amd_util.c
new file mode 100644 (file)
index 0000000..2fa31b9
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <aul.h>
+#include <aul_sock.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <pkgmgr-info.h>
+
+#include "amd_config.h"
+#include "amd_util.h"
+#include "amd_request.h"
+#include "amd_appinfo.h"
+#include "amd_app_status.h"
+#include "amd_socket.h"
+#include "amd_cynara.h"
+
+#define OSP_K_DATACONTROL_PROVIDER "__OSP_DATACONTROL_PROVIDER__"
+#define MAX_NR_OF_DESCRIPTORS 2
+#define AMD_LOG_BUFFER_SIZE 10000
+#define AMD_LOG_BUFFER_STRING_SIZE 128
+#define AMD_LOG_FILE "/run/aul/log/amd.log"
+
+static int log_index;
+static int log_fd;
+static GHashTable *__dc_socket_pair_hash;
+static int datacontrol_result;
+
+int _util_save_log(const char *tag, const char *message)
+{
+       int ret;
+       int offset;
+       time_t now;
+       char time_buf[32] = {0,};
+       char buffer[AMD_LOG_BUFFER_STRING_SIZE];
+
+       if (log_fd < 0) {
+               _E("Invalid file descriptor");
+               return -1;
+       }
+
+       time(&now);
+       ctime_r(&now, time_buf);
+       if (log_index != 0)
+               offset = lseek(log_fd, 0, SEEK_CUR);
+       else
+               offset = lseek(log_fd, 0, SEEK_SET);
+
+       if (offset == -1)
+               _E("error in lseek: %d", errno);
+
+       snprintf(buffer, sizeof(buffer), "[%-6d] %-15s %-50s %s",
+                       log_index, tag, message, time_buf);
+
+       ret = write(log_fd, buffer, strlen(buffer));
+       if (ret < 0) {
+               _E("Cannot write the amd log: %d", ret);
+               return -1;
+       }
+
+       if (++log_index >= AMD_LOG_BUFFER_SIZE)
+               log_index = 0;
+
+       return 0;
+}
+
+static int __init_log(void)
+{
+       int offset;
+
+       log_fd = open(AMD_LOG_FILE, O_CREAT | O_WRONLY, 0644);
+       if (log_fd < 0) {
+               _E("Failed to open %s - %d", AMD_LOG_FILE, errno);
+               return -1;
+       }
+
+       offset = lseek(log_fd, 0, SEEK_END);
+       if (offset != 0) {
+               log_index = (int)(offset / AMD_LOG_BUFFER_STRING_SIZE);
+               if (log_index >= AMD_LOG_BUFFER_SIZE) {
+                       log_index = 0;
+                       lseek(log_fd, 0, SEEK_SET);
+               }
+       }
+
+       return 0;
+}
+
+static int __send_message(int sock, const struct iovec *vec, int vec_size,
+               const int *desc, int nr_desc)
+{
+       struct msghdr msg = {0,};
+       int sndret;
+       int desclen = 0;
+       struct cmsghdr *cmsg = NULL;
+       char buff[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS)] = {0,};
+
+       if (vec == NULL || vec_size < 1)
+               return -EINVAL;
+       if (nr_desc < 0 || nr_desc > MAX_NR_OF_DESCRIPTORS)
+               return -EINVAL;
+       if (desc == NULL)
+               nr_desc = 0;
+
+       msg.msg_iov = (struct iovec *)vec;
+       msg.msg_iovlen = vec_size;
+
+       /* sending ancillary data */
+       if (nr_desc > 0) {
+               msg.msg_control = buff;
+               msg.msg_controllen = sizeof(buff);
+               cmsg = CMSG_FIRSTHDR(&msg);
+               if (cmsg == NULL)
+                       return -EINVAL;
+
+               /* packing files descriptors */
+               if (nr_desc > 0) {
+                       cmsg->cmsg_level = SOL_SOCKET;
+                       cmsg->cmsg_type = SCM_RIGHTS;
+                       desclen = cmsg->cmsg_len =
+                               CMSG_LEN(sizeof(int) * nr_desc);
+                       memcpy((int *)CMSG_DATA(cmsg), desc,
+                                       sizeof(int) * nr_desc);
+                       cmsg = CMSG_NXTHDR(&msg, cmsg);
+                       _D("packing file descriptors done");
+               }
+
+               /* finished packing updating the corect length */
+               msg.msg_controllen = desclen;
+       } else {
+               msg.msg_control = NULL;
+               msg.msg_controllen = 0;
+       }
+
+       sndret = sendmsg(sock, &msg, 0);
+       _D("sendmsg ret : %d", sndret);
+       if (sndret < 0)
+               return -errno;
+
+       return sndret;
+}
+
+static int __dispatch_get_mp_socket_pair(request_h req)
+{
+       int handles[2] = {0, 0};
+       struct iovec vec[3];
+       int msglen = 0;
+       char buffer[1024];
+       int ret = 0;
+
+       if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, handles) != 0) {
+               _E("error create socket pair");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       if (handles[0] == -1) {
+               _E("error socket open");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       _D("amd send mp fd : [%d, %d]", handles[0], handles[1]);
+       vec[0].iov_base = buffer;
+       vec[0].iov_len = strlen(buffer) + 1;
+
+       msglen = __send_message(_request_get_fd(req), vec, 1, handles, 2);
+       if (msglen < 0) {
+               _E("Error[%d]: while sending message\n", -msglen);
+               _request_send_result(req, -1);
+               ret = -1;
+       }
+
+       close(handles[0]);
+       close(handles[1]);
+
+       return ret;
+}
+
+static int *__check_dc_socket_pair_handle(char *socket_pair_key,
+               const char *datacontrol_type)
+{
+       int *handles;
+
+       handles = g_hash_table_lookup(__dc_socket_pair_hash, socket_pair_key);
+       if (handles == NULL)
+               return NULL;
+
+       if (strcmp(datacontrol_type, "consumer") == 0) {
+               if (handles[0] == -1) {
+                       g_hash_table_remove(__dc_socket_pair_hash,
+                                       socket_pair_key);
+                       return NULL;
+               }
+       } else {
+               if (handles[1] == -1) {
+                       g_hash_table_remove(__dc_socket_pair_hash,
+                                       socket_pair_key);
+                       return NULL;
+               }
+       }
+
+       return handles;
+}
+
+static int __dispatch_get_dc_socket_pair(request_h req)
+{
+       const char *caller;
+       const char *callee;
+       const char *datacontrol_type;
+       char *socket_pair_key = NULL;
+       int socket_pair_key_len;
+       int *handles = NULL;
+       struct iovec vec[3];
+       int msglen = 0;
+       char buffer[1024];
+       bundle *kb = _request_get_bundle(req);
+
+       caller = bundle_get_val(kb, AUL_K_CALLER_APPID);
+       if (caller == NULL)
+               goto err_out;
+       callee = bundle_get_val(kb, AUL_K_CALLEE_APPID);
+       if (callee == NULL)
+               goto err_out;
+       datacontrol_type = bundle_get_val(kb, "DATA_CONTROL_TYPE");
+
+       socket_pair_key_len = strlen(caller) + strlen(callee) + 2;
+
+       socket_pair_key = (char *)calloc(socket_pair_key_len, sizeof(char));
+       if (socket_pair_key == NULL) {
+               _E("calloc fail");
+               goto err_out;
+       }
+
+       snprintf(socket_pair_key, socket_pair_key_len, "%s_%s", caller, callee);
+       _D("socket pair key : %s", socket_pair_key);
+
+       handles = __check_dc_socket_pair_handle(socket_pair_key,
+                       datacontrol_type);
+       if (handles == NULL) {
+               handles = (int *)calloc(2, sizeof(int));
+               if (handles == NULL) {
+                       _E("calloc fail");
+                       goto err_out;
+               }
+
+               if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, handles) != 0) {
+                       _E("error create socket pair");
+                       free(handles);
+                       handles = NULL;
+                       goto err_out;
+               }
+
+               if (handles[0] == -1 || handles[1] == -1) {
+                       _E("error socket open");
+                       free(handles);
+                       handles = NULL;
+                       goto err_out;
+               }
+
+               g_hash_table_insert(__dc_socket_pair_hash,
+                               strdup(socket_pair_key), handles);
+               _D("New socket pair insert done.");
+       }
+
+       SECURE_LOGD("amd send fd : [%d, %d]", handles[0], handles[1]);
+       vec[0].iov_base = buffer;
+       vec[0].iov_len = 1;
+
+       _send_result_to_client_v2(_request_get_fd(req), 0);
+
+       if (datacontrol_type != NULL) {
+               _D("datacontrol_type : %s", datacontrol_type);
+               if (strcmp(datacontrol_type, "consumer") == 0) {
+                       msglen = __send_message(_request_get_fd(req), vec, 1,
+                                       &handles[0], 1);
+                       if (msglen < 0) {
+                               _E("Error[%d]: while sending message", -msglen);
+                               goto err_out;
+                       }
+                       close(handles[0]);
+                       handles[0] = -1;
+                       if (handles[1] == -1) {
+                               _D("remove from hash : %s", socket_pair_key);
+                               g_hash_table_remove(__dc_socket_pair_hash,
+                                               socket_pair_key);
+                       }
+
+               } else {
+                       msglen = __send_message(_request_get_fd(req), vec, 1,
+                                       &handles[1], 1);
+                       if (msglen < 0) {
+                               _E("Error[%d]: while sending message", -msglen);
+                               goto err_out;
+                       }
+                       close(handles[1]);
+                       handles[1] = -1;
+                       if (handles[0] == -1) {
+                               _D("remove from hash : %s", socket_pair_key);
+                               g_hash_table_remove(__dc_socket_pair_hash,
+                                               socket_pair_key);
+                       }
+               }
+       }
+       SECURE_LOGD("send_message msglen : [%d]\n", msglen);
+       if (socket_pair_key)
+               free(socket_pair_key);
+
+       return 0;
+
+err_out:
+       _request_send_result(req, -1);
+       if (socket_pair_key) {
+               g_hash_table_remove(__dc_socket_pair_hash, socket_pair_key);
+               free(socket_pair_key);
+       }
+
+       return -1;
+}
+
+static int __dispatch_app_set_process_group(request_h req)
+{
+       int owner_pid;
+       int child_pid;
+       bundle *kb = NULL;
+       const char *child_appid;
+       const char *child_pkgid = NULL;
+       const struct appinfo *ai;
+       const char *str_pid;
+       app_status_h app_status;
+       int ret;
+
+       kb = _request_get_bundle(req);
+       if (kb == NULL) {
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       str_pid = bundle_get_val(kb, AUL_K_OWNER_PID);
+       if (str_pid == NULL) {
+               _E("No owner pid");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       owner_pid = atoi(str_pid);
+       str_pid = bundle_get_val(kb, AUL_K_CHILD_PID);
+       if (str_pid == NULL) {
+               _E("No child pid");
+               _request_send_result(req, -1);
+               return -1;
+       }
+
+       child_pid = atoi(str_pid);
+       app_status = _app_status_find(child_pid);
+       if (app_status) {
+               child_appid = _app_status_get_appid(app_status);
+               ai = _appinfo_find(_request_get_target_uid(req), child_appid);
+               child_pkgid = _appinfo_get_value(ai, AIT_PKGID);
+       }
+
+       ret = aul_send_app_group_signal(owner_pid, child_pid, child_pkgid);
+
+       _request_send_result(req, ret);
+       return 0;
+}
+
+struct checker_info {
+       caller_info_h caller;
+       request_h req;
+};
+
+int __datacontrol_privilege_func(const char *privilege_name, void *user_data)
+{
+       int ret;
+       struct checker_info *info = (struct checker_info*)user_data;
+
+       ret = _cynara_simple_checker(info->caller, info->req,
+                       (void *)privilege_name);
+       if (ret >= 0 && datacontrol_result == AMD_CYNARA_UNKNOWN)
+               return ret;
+
+       datacontrol_result = ret;
+       return ret;
+}
+
+static int __datacontrol_provider_checker(caller_info_h info, request_h req,
+               void *data)
+{
+       bundle *b;
+       char *provider_id;
+       char *type;
+       char *data_type;
+       int ret;
+       struct checker_info checker = {
+               .caller = info,
+               .req = req
+       };
+
+       b = _request_get_bundle(req);
+       if (b == NULL)
+               return -1;
+
+       ret = bundle_get_str(b, "DATA_CONTROL_TYPE", &type);
+       if (ret < 0)
+               return -1;
+
+       if (strcmp(type, "provider") == 0)
+               return 0;
+
+       ret = bundle_get_str(b, OSP_K_DATACONTROL_PROVIDER, &provider_id);
+       if (ret < 0)
+               return -1;
+
+       ret = bundle_get_str(b, "DATA_CONTROL_DATA_TYPE", &data_type);
+       if (ret < 0)
+               return -1;
+
+       datacontrol_result = 0;
+
+       ret = pkgmgrinfo_appinfo_usr_foreach_datacontrol_privileges(provider_id,
+                       data_type, __datacontrol_privilege_func,
+                       &checker, _request_get_target_uid(req));
+       if (ret < 0) {
+               _E("pkgmgrinfo_appinfo_usr_foreach_datacontrol_privileges failed");
+               return -1;
+       }
+
+       return datacontrol_result;
+}
+
+static request_cmd_dispatch __dispatch_table[] = {
+       {
+               .cmd = APP_GET_DC_SOCKET_PAIR,
+               .callback = __dispatch_get_dc_socket_pair
+       },
+       {
+               .cmd = APP_GET_MP_SOCKET_PAIR,
+               .callback = __dispatch_get_mp_socket_pair
+       },
+       {
+               .cmd = APP_SET_PROCESS_GROUP,
+               .callback = __dispatch_app_set_process_group
+       },
+};
+
+static cynara_checker __cynara_checkers[] = {
+       {
+               .cmd = APP_GET_DC_SOCKET_PAIR,
+               .checker = __datacontrol_provider_checker,
+               .data = NULL,
+       },
+};
+
+static void __free_socket_pair(gpointer data)
+{
+       int *handles = (int *)data;
+
+       if (handles == NULL)
+               return;
+
+       if (handles[0] > 0)
+               close(handles[0]);
+       if (handles[1] > 0)
+               close(handles[1]);
+       free(handles);
+}
+
+int _util_init(void)
+{
+       int r;
+
+       if (__init_log() < 0)
+               return -1;
+
+       __dc_socket_pair_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+                       free, __free_socket_pair);
+       if (__dc_socket_pair_hash == NULL) {
+               _E("Failed to create socket pair table");
+               return -1;
+       }
+
+       r = _request_register_cmds(__dispatch_table,
+                       ARRAY_SIZE(__dispatch_table));
+       if (r < 0) {
+               _E("Failed to register cmds");
+               return -1;
+       }
+
+       r = _cynara_register_checkers(__cynara_checkers,
+                       ARRAY_SIZE(__cynara_checkers));
+       if (r < 0) {
+               _E("Failed to register checkers");
+               return -1;
+       }
+
+       return 0;
+}
+
+void _util_fini(void)
+{
+       if (log_fd > 0)
+               close(log_fd);
+
+       if (__dc_socket_pair_hash) {
+               g_hash_table_destroy(__dc_socket_pair_hash);
+               __dc_socket_pair_hash = NULL;
+       }
+}