From 2764ae990b2eee860c66fb389d6dcfdd041d1022 Mon Sep 17 00:00:00 2001 From: "minhoon.yi" Date: Tue, 25 Jul 2017 20:03:46 +0900 Subject: [PATCH] AEGIS_TEST! Change-Id: I41cf7e050f9759426d7e572bf29ffaae6458a8ca --- AUTHORS | 23 +- CMakeLists.txt | 58 + LICENSE | 204 +++ inc/amd_app_com.h | 36 + inc/amd_app_group.h | 68 + inc/amd_app_property.h | 53 + inc/amd_app_status.h | 102 ++ inc/amd_appinfo.h | 102 ++ inc/amd_cooldown.h | 37 + inc/amd_cynara.h | 27 + inc/amd_extractor.h | 30 + inc/amd_inotify.h | 28 + inc/amd_input.h | 23 + inc/amd_launch.h | 55 + inc/amd_login_monitor.h | 36 + inc/amd_request.h | 41 + inc/amd_rua.h | 30 + inc/amd_screen_connector.h | 45 + inc/amd_share.h | 28 + inc/amd_signal.h | 46 + inc/amd_socket.h | 40 + inc/amd_splash_screen.h | 35 + inc/amd_suspend.h | 37 + inc/amd_util.h | 59 + inc/amd_wayland.h | 27 + inc/amd_widget.h | 52 + inc/app_signal.h | 116 ++ inc/aul_svc_priv_key.h | 38 + packaging/ac.conf | 15 + packaging/ac.service | 24 + packaging/ac.socket | 7 + packaging/amd.manifest | 6 + packaging/amd.spec | 146 ++ src/amd_app_com.c | 373 +++++ src/amd_app_group.c | 1688 +++++++++++++++++++ src/amd_app_property.c | 741 +++++++++ src/amd_app_status.c | 1840 +++++++++++++++++++++ src/amd_appinfo.c | 1973 ++++++++++++++++++++++ src/amd_cooldown.c | 164 ++ src/amd_cynara.c | 581 +++++++ src/amd_extractor.c | 296 ++++ src/amd_inotify.c | 239 +++ src/amd_input.c | 465 ++++++ src/amd_launch.c | 1983 ++++++++++++++++++++++ src/amd_login_monitor.c | 547 ++++++ src/amd_main.c | 350 ++++ src/amd_request.c | 3927 ++++++++++++++++++++++++++++++++++++++++++++ src/amd_rua.c | 437 +++++ src/amd_screen_connector.c | 956 +++++++++++ src/amd_share.c | 480 ++++++ src/amd_signal.c | 635 +++++++ src/amd_socket.c | 266 +++ src/amd_splash_screen.c | 786 +++++++++ src/amd_suspend.c | 367 +++++ src/amd_util.c | 152 ++ src/amd_wayland.c | 215 +++ src/amd_widget.c | 980 +++++++++++ 57 files changed, 22095 insertions(+), 20 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 inc/amd_app_com.h create mode 100644 inc/amd_app_group.h create mode 100644 inc/amd_app_property.h create mode 100644 inc/amd_app_status.h create mode 100644 inc/amd_appinfo.h create mode 100644 inc/amd_cooldown.h create mode 100644 inc/amd_cynara.h create mode 100644 inc/amd_extractor.h create mode 100644 inc/amd_inotify.h create mode 100644 inc/amd_input.h create mode 100644 inc/amd_launch.h create mode 100644 inc/amd_login_monitor.h create mode 100644 inc/amd_request.h create mode 100644 inc/amd_rua.h create mode 100644 inc/amd_screen_connector.h create mode 100644 inc/amd_share.h create mode 100644 inc/amd_signal.h create mode 100644 inc/amd_socket.h create mode 100644 inc/amd_splash_screen.h create mode 100644 inc/amd_suspend.h create mode 100644 inc/amd_util.h create mode 100644 inc/amd_wayland.h create mode 100644 inc/amd_widget.h create mode 100644 inc/app_signal.h create mode 100644 inc/aul_svc_priv_key.h create mode 100644 packaging/ac.conf create mode 100644 packaging/ac.service create mode 100644 packaging/ac.socket create mode 100644 packaging/amd.manifest create mode 100644 packaging/amd.spec create mode 100644 src/amd_app_com.c create mode 100644 src/amd_app_group.c create mode 100644 src/amd_app_property.c create mode 100644 src/amd_app_status.c create mode 100644 src/amd_appinfo.c create mode 100644 src/amd_cooldown.c create mode 100644 src/amd_cynara.c create mode 100644 src/amd_extractor.c create mode 100644 src/amd_inotify.c create mode 100644 src/amd_input.c create mode 100644 src/amd_launch.c create mode 100644 src/amd_login_monitor.c create mode 100644 src/amd_main.c create mode 100644 src/amd_request.c create mode 100644 src/amd_rua.c create mode 100644 src/amd_screen_connector.c create mode 100644 src/amd_share.c create mode 100644 src/amd_signal.c create mode 100644 src/amd_socket.c create mode 100644 src/amd_splash_screen.c create mode 100644 src/amd_suspend.c create mode 100644 src/amd_util.c create mode 100644 src/amd_wayland.c create mode 100644 src/amd_widget.c diff --git a/AUTHORS b/AUTHORS index d4b78ce..064881e 100644 --- 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 +Sewook Park +Jaeho Lee diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ac46d47 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,58 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +PROJECT(amd C) +AUX_SOURCE_DIRECTORY(src SOURCES) + +ADD_DEFINITIONS("-DSHARE_PREFIX=\"${SHARE_INSTALL_PREFIX}/aul\"") +IF(with_wayland) + ADD_DEFINITIONS("-DWAYLAND") +ENDIF(with_wayland) +IF(with_x11) + ADD_DEFINITIONS("-DX11") +ENDIF(with_x11) + +IF(_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP) + ADD_DEFINITIONS("-DTIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP") +ENDIF(_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP) +IF(_TIZEN_FEATURE_BLOCK_INPUT) + ADD_DEFINITIONS("-DTIZEN_FEATURE_BLOCK_INPUT") +ENDIF(_TIZEN_FEATURE_BLOCK_INPUT) +IF(_TIZEN_FEATURE_AUTO_ROTATION) + ADD_DEFINITIONS("-DTIZEN_FEATURE_AUTO_ROTATION") +ENDIF(_TIZEN_FEATURE_AUTO_ROTATION) + +# Set required packages +INCLUDE(FindPkgConfig) + +SET(AMD_PKG_CHECK_MODULES dlog rua aul glib-2.0 gio-2.0 vconf pkgmgr-info pkgmgr bundle libsystemd-daemon cynara-client cynara-creds-socket cynara-session cert-svc-vcore libtzplatform-config xkbcommon sensor security-manager ttrace app2sd capi-system-info) +IF (with_wayland) + pkg_check_modules(pkgs REQUIRED ${AMD_PKG_CHECK_MODULES} wayland-client tizen-extension-client wayland-tbm-client tizen-launch-client) +ENDIF(with_wayland) +IF(with_x11) + pkg_check_modules(pkgs REQUIRED ${AMD_PKG_CHECK_MODULES} ) +ENDIF(with_x11) + +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") + +ADD_EXECUTABLE(amd ${SOURCES}) +SET_TARGET_PROPERTIES(amd PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS} -fPIE") +TARGET_LINK_LIBRARIES(amd ${pkgs_LDFLAGS} "-pie") +INSTALL(TARGETS amd DESTINATION bin) + + diff --git a/LICENSE b/LICENSE new file mode 100644 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_app_com.h b/inc/amd_app_com.h new file mode 100644 index 0000000..5782450 --- /dev/null +++ b/inc/amd_app_com.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 - 2016 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 + +int _app_com_broker_init(void); +int _app_com_broker_fini(void); +int _app_com_client_remove(int cpid); +int _app_com_add_endpoint(const char *endpoint, unsigned int propagate, + const char *assoc_priv); +int _app_com_remove_endpoint(const char *endpoint); +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); +int _app_com_leave(const char *endpoint, int cpid); +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_group.h b/inc/amd_app_group.h new file mode 100644 index 0000000..b186681 --- /dev/null +++ b/inc/amd_app_group.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 - 2016 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 +#include +#include +#include + +typedef enum { + APP_GROUP_LAUNCH_MODE_SINGLE = 0, + APP_GROUP_LAUNCH_MODE_GROUP, + APP_GROUP_LAUNCH_MODE_CALLER, + APP_GROUP_LAUNCH_MODE_SINGLETON, +} app_group_launch_mode; + +void _app_group_remove(int pid); +int _app_group_get_window(int pid); +int _app_group_set_window(int pid, int wid); +void _app_group_get_leader_pids(int *cnt, int **pids); +void _app_group_get_group_pids(int leader_pid, int *cnt, int **pids); +bool _app_group_is_leader_pid(int pid); +bool _app_group_is_group_app(bundle *kb, uid_t uid); +bool _app_group_is_sub_app(int pid); +void _app_group_reroute(int pid); +void _app_group_clear_top(int pid, uid_t uid); +int _app_group_get_leader_pid(int pid); +void _app_group_set_dead_pid(int pid); +int _app_group_get_status(int pid); +int _app_group_set_status(int pid, int status, bool force); +int _app_group_get_fg_flag(int pid); +int _app_group_set_hint(int pid, bundle *kb); +int _app_group_find_second_leader(int lpid); +void _app_group_remove_leader_pid(int lpid); +int _app_group_can_start_app(const char *appid, bundle *b, bool *can_attach, + int *lpid, app_group_launch_mode *mode, uid_t uid); +void _app_group_start_app(int pid, bundle *b, int lpid, bool can_attach, + app_group_launch_mode mode); +int _app_group_find_singleton(const char *appid, int *found_pid, + int *found_lpid); +int _app_group_can_reroute(int pid); +void _app_group_lower(int pid, int *exit); +void _app_group_restart_app(int pid, bundle *b); +int _app_group_find_pid_from_recycle_bin(const char *appid); +void _app_group_get_idle_pids(int *cnt, int **pids); +void _app_group_remove_from_recycle_bin(int pid); +int _app_group_get_next_caller_pid(int pid); +int _app_group_activate_below(int pid, const char *below_appid); +int _app_group_activate_above(int pid, const char *above_appid); +int _app_group_attach(const char *parent_appid, const char *child_appid, + uid_t uid); +int _app_group_detach(const char *child_appid, uid_t uid); +int _app_group_init(void); +void _app_group_fini(void); diff --git a/inc/amd_app_property.h b/inc/amd_app_property.h new file mode 100644 index 0000000..7981c35 --- /dev/null +++ b/inc/amd_app_property.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016 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 +#include + +#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_put(app_property_h app_property, const char *checksum, const char *appid); +const char *_app_property_cache_get(app_property_h app_property, const char *checksum); +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 index 0000000..94d0319 --- /dev/null +++ b/inc/amd_app_status.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 - 2016 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 +#include +#include +#include +#include + +#include "amd_appinfo.h" + +typedef enum { + AT_SERVICE_APP, + AT_UI_APP, + AT_WIDGET_APP, + AT_WATCH_APP, +} app_type_e; + +typedef struct _shared_info_t { + char *owner_appid; + private_sharing_req *handle; +} shared_info_t; + +typedef struct app_status_s *app_status_h; + +void _app_status_send_fault_dead_for_update_app(const char *pkgid); +void _app_status_send_fault_dead_for_oom_apps(void); +void _app_status_fault_recovery(int pid, int uid, const char *pkgid, + const char *appid, int type, bool is_exit_notified); +int _app_status_set_is_exit_notified(app_status_h app_status, bool is_exit_notified); +bool _app_status_get_is_exit_notified(app_status_h app_status); +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); +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); +int _app_status_add_shared_info(app_status_h app_status, shared_info_t *info); +int _app_status_clear_shared_info_list(app_status_h stat); +GList *_app_status_get_shared_info_list(app_status_h stat); +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 index 0000000..ac197ca --- /dev/null +++ b/inc/amd_appinfo.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 - 2016 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 +#include +#include + +#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_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); +void _appinfo_reload(void); +int _appinfo_load(uid_t uid); +void _appinfo_unload(uid_t uid); +bool _appinfo_is_pkg_updating(const char *pkgid); diff --git a/inc/amd_cooldown.h b/inc/amd_cooldown.h new file mode 100644 index 0000000..34dc0dd --- /dev/null +++ b/inc/amd_cooldown.h @@ -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. + */ + +#pragma once + +#include "amd_appinfo.h" + +#define APP_SUPPORT_MODE_VIP_APPLICATION 0x00000010 + +#define COOLDOWN_STATUS_RELEASE "Release" +#define COOLDOWN_STATUS_RELEASE_STRING_LEN 7 +#define COOLDOWN_STATUS_LIMITACTION "LimitAction" +#define COOLDOWN_STATUS_LIMITACTION_STRING_LEN 11 + +/* cooldown status values */ +enum cooldown_status_val { + COOLDOWN_RELEASE, + COOLDOWN_WARNING, + COOLDOWN_LIMIT, +}; + +int _cooldown_get_status(void); +int _cooldown_check_mode(const struct appinfo *ai); +int _cooldown_init(void); +void _cooldown_fini(void); diff --git a/inc/amd_cynara.h b/inc/amd_cynara.h new file mode 100644 index 0000000..eb9f248 --- /dev/null +++ b/inc/amd_cynara.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015 - 2016 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_CYNARA_H__ +#define __AMD_CYNARA_H__ + +#include "amd_request.h" + +int _cynara_init(void); +void _cynara_finish(void); +int _cynara_check_privilege(request_h req); + +#endif /* __AMD_CYNARA_H__ */ + diff --git a/inc/amd_extractor.h b/inc/amd_extractor.h new file mode 100644 index 0000000..18f179d --- /dev/null +++ b/inc/amd_extractor.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 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 + +#include "amd_appinfo.h" + +typedef char **(_extractor_mountable)(const struct appinfo *ai); + +char **_extractor_mountable_get_tep_paths(const struct appinfo *ai); +char **_extractor_mountable_get_tpk_paths(const struct appinfo *ai); +void _extractor_mount(const struct appinfo *ai, bundle *kb, + _extractor_mountable mountable); +void _extractor_unmount(int pid, _extractor_mountable mountable); + diff --git a/inc/amd_inotify.h b/inc/amd_inotify.h new file mode 100644 index 0000000..8db8bc7 --- /dev/null +++ b/inc/amd_inotify.h @@ -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 +#include + +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_input.h b/inc/amd_input.h new file mode 100644 index 0000000..e8c1c35 --- /dev/null +++ b/inc/amd_input.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016 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 _input_init(void); +int _input_fini(void); +int _input_lock(void); +int _input_unlock(void); + diff --git a/inc/amd_launch.h b/inc/amd_launch.h new file mode 100644 index 0000000..c3bd036 --- /dev/null +++ b/inc/amd_launch.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000 - 2016 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 +#include +#include +#include + +#include "amd_request.h" +#include "amd_util.h" +#include "amd_appinfo.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 + +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_add_fgmgr(int pid); +void _launch_remove_fgmgr(int pid); diff --git a/inc/amd_login_monitor.h b/inc/amd_login_monitor.h new file mode 100644 index 0000000..6b56889 --- /dev/null +++ b/inc/amd_login_monitor.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 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__ + +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_request.h b/inc/amd_request.h new file mode 100644 index 0000000..5966a69 --- /dev/null +++ b/inc/amd_request.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000 - 2016 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 +#include +#include + +typedef struct request_s *request_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); +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_init(void); +void _request_fini(void); diff --git a/inc/amd_rua.h b/inc/amd_rua.h new file mode 100644 index 0000000..bd49ffa --- /dev/null +++ b/inc/amd_rua.h @@ -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 +#include +#include + +int _rua_update_screen_info(int pid, unsigned int surf); +int _rua_add_info(int pid, bool new_instance); +const char *_rua_get_image_path(int pid); +int _rua_delete_info(bundle *b, uid_t uid); +int _rua_usr_init(uid_t uid); +void _rua_usr_fini(uid_t uid); +int _rua_init(void); +void _rua_fini(void); diff --git a/inc/amd_screen_connector.h b/inc/amd_screen_connector.h new file mode 100644 index 0000000..f84625b --- /dev/null +++ b/inc/amd_screen_connector.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016 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 + +int _screen_connector_send_update_request(const char *appid, + const char *instance_id, uid_t uid); +int _screen_connector_add_app_screen(int pid, unsigned int surf, + const char *instance_id, uid_t uid); +int _screen_connector_remove_app_screen(int pid, const char *instance_id, + uid_t uid); +int _screen_connector_remove_app_screen_v2(int pid, uid_t uid); +int _screen_connector_update_app_screen(int pid, unsigned int surf, uid_t uid); +int _screen_connector_add_screen_viewer(int pid, int screen_type, + bool priv, unsigned int ref, uid_t uid); +int _screen_connector_remove_screen_viewer(int pid, int screen_type, + bool priv, unsigned int ref, uid_t uid); +int _screen_connector_remove_screen_viewer_v2(int pid, uid_t uid); +int _screen_connector_usr_init(uid_t uid); +void _screen_connector_usr_fini(uid_t uid); +int _screen_connector_init(void); +void _screen_connector_fini(void); +const char *_screen_connector_get_appid_by_surface_id(unsigned int surf, + uid_t uid); +const char *_screen_connector_get_instance_id_by_surface_id(unsigned int surf, + uid_t uid); +int _screen_connector_update_screen_viewer_status(int pid, int status, + unsigned int surf, uid_t uid); +unsigned int _screen_connector_get_surface_id(const char *instance_id, + uid_t uid); diff --git a/inc/amd_share.h b/inc/amd_share.h new file mode 100644 index 0000000..59603f9 --- /dev/null +++ b/inc/amd_share.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 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_app_status.h" + +typedef struct shared_info_main_s *shared_info_h; + +shared_info_h _temporary_permission_create(int caller_pid, const char *appid, + bundle *kb, uid_t uid); +int _temporary_permission_destroy(shared_info_h handle); +int _temporary_permission_apply(int pid, uid_t uid, shared_info_h handle); +int _temporary_permission_drop(int pid, uid_t uid); + diff --git a/inc/amd_signal.h b/inc/amd_signal.h new file mode 100644 index 0000000..8aba2bd --- /dev/null +++ b/inc/amd_signal.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 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 +#include + +#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, char *flag, + unsigned int timeout); +int _signal_send_display_unlock_state(const char *state, 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 index 0000000..2d6f791 --- /dev/null +++ b/inc/amd_socket.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000 - 2016 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 +#include +#include + +#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_splash_screen.h b/inc/amd_splash_screen.h new file mode 100644 index 0000000..fdf21ab --- /dev/null +++ b/inc/amd_splash_screen.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 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 +#include +#include + +#include "amd_appinfo.h" + +typedef struct splash_image_s *splash_image_h; + +splash_image_h _splash_screen_get_image(int pid); +splash_image_h _splash_screen_create_image(const struct appinfo *ai, + bundle *kb, int cmd, bool is_subapp); +void _splash_screen_send_image(splash_image_h si); +void _splash_screen_send_pid(splash_image_h si, int pid); +void _splash_screen_set_effect_type(int pid, const char *appid, bool is_subapp); +void _splash_screen_destroy_image(splash_image_h si); +int _splash_screen_init(void); + diff --git a/inc/amd_suspend.h b/inc/amd_suspend.h new file mode 100644 index 0000000..0f2e8b2 --- /dev/null +++ b/inc/amd_suspend.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 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_appinfo.h" + +#define SUSPEND_TYPE_EXCLUDE "exclude" +#define SUSPEND_TYPE_INCLUDE "include" + +enum suspend_status_e { + SUSPEND_STATUS_EXCLUDE, + SUSPEND_STATUS_INCLUDE, +}; + +bool _suspend_is_allowed_background(const struct appinfo *ai); +void _suspend_add_timer(int pid, const struct appinfo *ai); +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 index 0000000..faaf364 --- /dev/null +++ b/inc/amd_util.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000 - 2016 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 + +#include +#include +#include +#include + +#define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "AUL_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); +bool _util_check_oom(void); diff --git a/inc/amd_wayland.h b/inc/amd_wayland.h new file mode 100644 index 0000000..3cbd26a --- /dev/null +++ b/inc/amd_wayland.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016 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 + +int _wayland_add_registry_listener( + struct wl_registry_listener *registry_listener, + void *data); +struct wl_display *_wayland_get_display(void); +int _wayland_init(void); +void _wayland_finish(void); + diff --git a/inc/amd_widget.h b/inc/amd_widget.h new file mode 100644 index 0000000..69557c3 --- /dev/null +++ b/inc/amd_widget.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 - 2016 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_WIDGET_H__ +#define __AMD_WIDGET_H__ + +#include "amd_request.h" + +int _widget_add(const char *widget_id, const char *instance_id, int pid, + uid_t uid); +int _widget_del(const char *widget_id, const char *instance_id); +int _widget_list(const char *widget_id, request_h req); +int _widget_update(const char *widget_id, request_h req); +int _widget_cleanup(int pid, uid_t uid); +int _widget_is_faulted(const char *widget_id, int pid, + uid_t uid, bool *is_faulted); +bool _widget_exist(int pid, uid_t uid); +char *_widget_get_id(int pid, uid_t uid); +int _widget_send_status_to_viewer(int pid, uid_t uid, const char *widget_id, + int viewer_pid, aul_widget_instance_event_e status); +int _widget_send_dead_signal(int pid, uid_t uid, const char *pkgid); +int _widget_count(const char *widget_id, uid_t uid); +int _widget_get_pid(const char *widget_id, const char *instance_id); +int _widget_verify_cmd(request_h req); +int _widget_is_dying(int pid, uid_t uid); +int _widget_init(void); +void _widget_fini(void); +int _widget_add_update_info(const char *pkg_id, int pid, uid_t uid); +int _widget_send_dead_signal_for_update_widget(const char *pkgid); +int _widget_send_dead_signal_for_faulted(int pid, uid_t uid, + const char *pkgid, const char *widget_id); +void _widget_restart_faulted(void); +void _widget_dead_handler(int pid, int uid, const char *pkgid, int caller_pid, + bool normal_exit, bool can_restart); +void _widget_verify_instance(bundle *kb, int pid, uid_t uid); +int _widget_send_running_info(request_h req); + +#endif /* __AMD_WIDGET_H__ */ + diff --git a/inc/app_signal.h b/inc/app_signal.h new file mode 100644 index 0000000..ed850cf --- /dev/null +++ b/inc/app_signal.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000 - 2015 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 RESOURCED_PATH_CORE "/Org/Tizen/ResourceD/Process" +#define RESOURCED_INTERFACE_CORE "org.tizen.resourced.process" + +#define RESOURCED_SIGNAL_PROCESS_STATUS "ProcStatus" + +#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 RESOURCED_PROC_OBJECT "/Org/Tizen/ResourceD/Process" +#define RESOURCED_PROC_INTERFACE "org.tizen.resourced.process" +#define RESOURCED_PROC_METHOD "ProcExclude" + +#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_ALLOWED_BG_ATTRIBUTE 0x100 +#define RESOURCED_BACKGROUND_MANAGEMENT_ATTRIBUTE 0x200 +#define RESOURCED_API_VER_2_4_ATTRIBUTE 0x400 + +#define RESOURCED_PROC_PRELAUNCH_SIGNAL "ProcPrelaunch" +#define RESOURCED_PROC_WATCHDOG_SIGNAL "ProcWatchdog" +#define RESOURCED_PROC_GROUP_SIGNAL "ProcGroup" + +#define PROC_TYPE_EXCLUDE "exclude" +#define PROC_TYPE_INCLUDE "include" +#define PROC_TYPE_WAKEUP "wakeup" + +#define TEP_BUS_NAME "org.tizen.system.deviced" +#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_BUS_NAME "org.tizen.system.deviced" +#define SYSTEM_OBJECT_PATH "/Org/Tizen/System/DeviceD/PmQos" +#define SYSTEM_INTERFACE_NAME "org.tizen.system.deviced.PmQos" +#define SYSTEM_METHOD_NAME "AppLaunch" + +#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 index 0000000..a3b03ae --- /dev/null +++ b/inc/aul_svc_priv_key.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 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/packaging/ac.conf b/packaging/ac.conf new file mode 100644 index 0000000..f06cc3a --- /dev/null +++ b/packaging/ac.conf @@ -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 index 0000000..9e87925 --- /dev/null +++ b/packaging/ac.service @@ -0,0 +1,24 @@ +# +# 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 +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 index 0000000..74bf73d --- /dev/null +++ b/packaging/ac.socket @@ -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 index 0000000..81ace0c --- /dev/null +++ b/packaging/amd.manifest @@ -0,0 +1,6 @@ + + + + + + diff --git a/packaging/amd.spec b/packaging/amd.spec new file mode 100644 index 0000000..6aedd87 --- /dev/null +++ b/packaging/amd.spec @@ -0,0 +1,146 @@ +%bcond_with x +%bcond_with wayland + +Name: amd +Summary: Application Management Daemon +Version: 0.2.1 +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-daemon) +BuildRequires: pkgconfig(cynara-client) +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-system-info) +%if %{with wayland} +BuildRequires: pkgconfig(wayland-client) +BuildRequires: pkgconfig(tizen-extension-client) +BuildRequires: pkgconfig(tizen-launch-client) +BuildRequires: pkgconfig(wayland-tbm-client) +%endif + +%if "%{?profile}" == "tv" +%define tizen_feature_terminate_unmanageable_app 0 +%define tizen_feature_block_input 0 +%define tizen_feature_auto_rotation 0 +%else +%if "%{?profile}" == "ivi" +%define tizen_feature_terminate_unmanageable_app 1 +%define tizen_feature_block_input 0 +%define tizen_feature_auto_rotation 0 +%else +%define tizen_feature_terminate_unmanageable_app 1 +%define tizen_feature_block_input 1 +%define tizen_feature_auto_rotation 1 +%endif +%endif + +%description +Application management daemon + +%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 +%if 0%{?tizen_feature_auto_rotation} +_TIZEN_FEATURE_AUTO_ROTATION=ON +%endif + +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +%cmake -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \ +%if %{with wayland} + -Dwith_wayland=TRUE \ +%endif +%if %{with x} + -Dwith_x11=TRUE \ +%endif + -D_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP:BOOL=${_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP} \ + -D_TIZEN_FEATURE_BLOCK_INPUT:BOOL=${_TIZEN_FEATURE_BLOCK_INPUT} \ + -D_TIZEN_FEATURE_AUTO_ROTATION:BOOL=${_TIZEN_FEATURE_AUTO_ROTATION} \ + . + +%__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 + +%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 +%caps(cap_kill,cap_dac_override=ep) %{_bindir}/amd + diff --git a/src/amd_app_com.c b/src/amd_app_com.c new file mode 100644 index 0000000..680c1d9 --- /dev/null +++ b/src/amd_app_com.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2015 - 2016 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 +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_app_com.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); +} + +int _app_com_broker_init(void) +{ + 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; + } + } + + return 0; +} + +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); +} + +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; +} + +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); + info->propagate = propagate; + info->clients = NULL; + + if (assoc_priv) + info->privilege = g_strdup(assoc_priv); + else + info->privilege = NULL; + + g_hash_table_insert(endpoint_tbl, info->endpoint, info); + + return AUL_APP_COM_R_ERROR_OK; +} + +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); + 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; +} + +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); + } +} + +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); +} diff --git a/src/amd_app_group.c b/src/amd_app_group.c new file mode 100644 index 0000000..b0aaa04 --- /dev/null +++ b/src/amd_app_group.c @@ -0,0 +1,1688 @@ +/* + * Copyright (c) 2015 - 2016 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_app_group.h" +#include "amd_launch.h" +#include "amd_request.h" +#include "amd_app_status.h" +#include "app_signal.h" +#include "amd_appinfo.h" +#include "amd_share.h" +#include "amd_suspend.h" +#include "amd_wayland.h" + +#define APP_SVC_K_LAUNCH_MODE "__APP_SVC_LAUNCH_MODE__" + +typedef struct _app_group_context_t { + int pid; + int wid; + int status; + int fg; + int group_sig; + int can_be_leader; + int reroute; + int caller_pid; + int can_shift; + int recycle; + app_group_launch_mode launch_mode; +} app_group_context_t; + +static struct wl_display *display; +static struct tizen_policy *tz_policy; +static int tz_policy_initialized; +static GHashTable *app_group_hash; +static int dead_pid = -1; +static int focused_leader_pid = -1; +static GList *recycle_bin; +extern char *home_appid; + +static void __wl_listener_cb(void *data, struct wl_registry *reg, + uint32_t id, const char *interface, uint32_t ver) +{ + if (!strcmp(interface, "tizen_policy")) { + if (!tz_policy) { + tz_policy = wl_registry_bind(reg, id, + &tizen_policy_interface, 1); + } + } +} + +static void __wl_listener_remove_cb(void *data, struct wl_registry *reg, + uint32_t id) +{ + if (tz_policy) { + tizen_policy_destroy(tz_policy); + tz_policy = NULL; + } +} + +static struct wl_registry_listener registry_listener = { + __wl_listener_cb, + __wl_listener_remove_cb +}; + +static int __wl_init(void) +{ + if (!display) { + display = _wayland_get_display(); + if (!display) { + _E("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) { + _E("__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) { + _E("__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) { + _E("__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) { + _E("__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) { + _E("__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 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 GList *__find_removable_apps(int from) +{ + int cnt; + int *pids = NULL; + GList *list = NULL; + bool found = false; + int i; + int j; + int *gpids = NULL; + int gcnt; + + _app_group_get_leader_pids(&cnt, &pids); + + for (i = 0; i < cnt; i++) { + _app_group_get_group_pids(pids[i], &gcnt, &gpids); + for (j = 0; j < gcnt; j++) { + if (gpids[j] == from) { + found = true; + continue; + } + + if (found) { + list = g_list_append(list, + GINT_TO_POINTER(gpids[j])); + } + } + + if (gpids != NULL) + free(gpids); + + if (found) + break; + } + + if (pids != NULL) + free(pids); + + return list; +} + +static void __prepare_to_suspend_services(int pid, uid_t uid) +{ + int ret; + int dummy; + + _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("error on suspend service for pid: %d", pid); +} + +static void __prepare_to_wake_services(int pid, uid_t uid) +{ + int ret; + int dummy; + + _D("[__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) + _E("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; + app_status_h app_status; + const struct appinfo *ai; + const char *appid; + const char *pkgid; + int bg_category; + uid_t uid; + + while (list) { + ac = (app_group_context_t *)list->data; + if (ac && (ac->fg != flag || force == true)) { + app_status = _app_status_find(ac->pid); + appid = _app_status_get_appid(app_status); + uid = _app_status_get_uid(app_status); + ai = _appinfo_find(uid, appid); + pkgid = _appinfo_get_value(ai, AIT_PKGID); + bg_category = (intptr_t)_appinfo_get_value(ai, + AIT_BG_CATEGORY); + if (flag) { + _D("Send FG signal %s", appid); + aul_send_app_status_change_signal(ac->pid, + appid, pkgid, STATUS_FOREGROUND, + APP_TYPE_UI); + if (!bg_category) { + _app_status_find_service_apps( + app_status, + STATUS_VISIBLE, + __prepare_to_wake_services, + false); + } + } else { + _D("send BG signal %s", appid); + aul_send_app_status_change_signal(ac->pid, + appid, pkgid, STATUS_BACKGROUND, + APP_TYPE_UI); + if (!bg_category) { + _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); + _suspend_add_timer(ac->pid, ai); + } + } + } + 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(cpid); + 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); + ac = (app_group_context_t *)i->data; + if (ac && ac->pid == lpid) { + __set_flag(i, cpid, flag, force); + break; + } + } +} + +static bool __is_visible(int cpid) +{ + int lpid = _app_group_get_leader_pid(cpid); + 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); + ac = (app_group_context_t *)i->data; + if (ac && ac->pid == lpid) { + while (i != NULL) { + ac = (app_group_context_t *)i->data; + if (ac && ac->status == STATUS_VISIBLE) + return true; + + i = g_list_next(i); + } + break; + } + } + + return false; +} + +static bool __can_attach_window(bundle *b, const char *appid, + app_group_launch_mode *launch_mode, uid_t uid) +{ + char *str = NULL; + const char *mode = NULL; + const struct appinfo *ai = NULL; + + ai = _appinfo_find(uid, appid); + mode = _appinfo_get_value(ai, 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; + else if (strcmp(mode, "singleton") == 0) + *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLETON; + + switch (*launch_mode) { + case APP_GROUP_LAUNCH_MODE_CALLER: + case APP_GROUP_LAUNCH_MODE_SINGLETON: + _D("launch mode from db is caller or singleton"); + + bundle_get_str(b, APP_SVC_K_LAUNCH_MODE, &str); + 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) +{ + char *str = NULL; + + bundle_get_str(b, AUL_SVC_K_CAN_BE_LEADER, &str); + if (str != NULL && strcmp(str, "true") == 0) + return true; + + return false; +} + +static int __get_previous_pid(int pid) +{ + int previous_pid = -1; + 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 == NULL) { + i = g_list_next(i); + continue; + } + + if (ac && ac->pid == pid) + return previous_pid; + + previous_pid = ac->pid; + i = g_list_next(i); + } + } + + return -1; +} + +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 void __group_add(int leader_pid, int pid, int wid, + app_group_launch_mode mode, int caller_pid, int can_shift, + int recycle) +{ + app_group_context_t *ac = NULL; + GList *list; + GList *tmp_list; + + ac = __detach_context_from_recycle_bin(pid); + if (ac == NULL) { + ac = malloc(sizeof(app_group_context_t)); + if (ac == NULL) { + _E("out of memory"); + return; + } + ac->pid = pid; + ac->wid = wid; + ac->fg = 0; + ac->can_be_leader = 0; + ac->reroute = 0; + 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 = 1; + else + ac->group_sig = 0; + + dead_pid = -1; + + 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) { + _E("pid exist"); + free(ac); + return; + } + } + + list = g_list_append(list, ac); + g_hash_table_insert(app_group_hash, GINT_TO_POINTER(leader_pid), list); + + if (ac->wid != 0) + _app_group_set_window(pid, ac->wid); +} + +static void __group_remove(int pid) +{ + int ppid = __get_previous_pid(pid); + + g_hash_table_foreach_remove(app_group_hash, __hash_table_cb, + GINT_TO_POINTER(pid)); + + if (ppid != -1) + _app_group_set_status(ppid, -1, false); +} + +static app_group_context_t *__get_context(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 ac; + + i = g_list_next(i); + } + } + + return NULL; +} + +static int __can_recycle(int pid) +{ + app_group_context_t *context = __get_context(pid); + + if (context) + return context->recycle; + + return 0; +} + +static int __can_reroute(int pid) +{ + app_group_context_t *context = __get_context(pid); + + if (context) + return context->reroute; + + return 0; +} + +static app_group_context_t *__context_dup(const app_group_context_t *context) +{ + app_group_context_t *dup; + + if (!context) { + _E("context is NULL."); + return NULL; + } + + dup = malloc(sizeof(app_group_context_t)); + if (!dup) { + _E("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; + const struct appinfo *ai; + app_status_h app_status; + uid_t uid; + + app_status = _app_status_find(context->pid); + uid = _app_status_get_uid(app_status); + + if (context->fg) { + appid = _app_status_get_appid(app_status); + ai = _appinfo_find(uid, appid); + pkgid = _appinfo_get_value(ai, AIT_PKGID); + + _D("send_signal BG %s", appid); + aul_send_app_status_change_signal(context->pid, appid, pkgid, + STATUS_BACKGROUND, APP_TYPE_UI); + _app_status_find_service_apps(app_status, STATUS_BG, + __prepare_to_suspend_services, true); + context->fg = 0; + } + recycle_bin = g_list_append(recycle_bin, context); + _temporary_permission_drop(context->pid, uid); +} + +void _app_group_remove(int pid) +{ + app_group_context_t *context; + + __group_remove(pid); + context = __detach_context_from_recycle_bin(pid); + if (context) + free(context); +} + +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(int pid) +{ + app_group_context_t *context = __get_context(pid); + + if (context) + return context->wid; + + return -1; +} + +int _app_group_set_window(int pid, int wid) +{ + GHashTableIter iter; + gpointer key; + gpointer value; + GList *list; + GList *i; + int previous_wid; + int caller_wid; + 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); + previous_wid = 0; + while (i != NULL) { + ac = (app_group_context_t *) i->data; + if (ac == NULL) { + i = g_list_next(i); + continue; + } + + if (ac && ac->pid == pid) { + ac->wid = wid; + if (previous_wid != 0) + __attach_window(previous_wid, wid); + + if (ac->can_shift && ac->caller_pid > 0) { + caller_wid = _app_group_get_window( + ac->caller_pid); + if (caller_wid != 0) { + __attach_window(caller_wid, + wid); + } + } + + i = g_list_next(i); + if (i) { + ac = (app_group_context_t *)i->data; + if (ac->wid != 0) + __attach_window(wid, ac->wid); + } + + return 0; + } + previous_wid = ac->wid; + i = g_list_next(i); + } + } + + return -1; +} + +void _app_group_clear_top(int pid, uid_t uid) +{ + int p; + int wid; + GList *list; + GList *itr; + + list = __find_removable_apps(pid); + if (list != NULL) { + itr = g_list_last(list); + while (itr != NULL) { + p = GPOINTER_TO_INT(itr->data); + if (p > 0) { + wid = _app_group_get_window(p); + __detach_window(wid); + aul_send_app_terminate_request_signal(p, + NULL, NULL, NULL); + _term_sub_app(p, uid); + _app_group_remove(p); + } + itr = g_list_previous(itr); + } + g_list_free(list); + } +} + +bool _app_group_is_group_app(bundle *kb, uid_t uid) +{ + char *str = NULL; + const char *mode; + char *appid = NULL; + const struct appinfo *ai; + + if (kb == NULL) + return false; + + bundle_get_str(kb, AUL_K_APPID, &appid); + if (appid == NULL) + return false; + + ai = _appinfo_find(uid, appid); + mode = _appinfo_get_value(ai, AIT_LAUNCH_MODE); + + if (mode != NULL && (strcmp(mode, "caller") == 0 || + strcmp(mode, "singleton") == 0)) { + bundle_get_str(kb, APP_SVC_K_LAUNCH_MODE, &str); + if (str != NULL && strcmp(str, "group") == 0) + return true; + } else if (mode != NULL && strcmp(mode, "group") == 0) { + return true; + } + + return false; +} + +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) { + _E("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; + } +} + +bool _app_group_is_leader_pid(int pid) +{ + int cnt; + int *pids = NULL; + int i; + + _app_group_get_leader_pids(&cnt, &pids); + for (i = 0; i < cnt; i++) { + if (pid == pids[i]) { + free(pids); + return true; + } + } + + if (pids != NULL) + free(pids); + + return false; +} + +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) { + _E("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; +} + +bool _app_group_is_sub_app(int pid) +{ + GHashTableIter iter; + gpointer key; + gpointer value; + GList *list; + GList *found; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + list = (GList *)value; + if (list != NULL) { + found = g_list_find_custom(list, GINT_TO_POINTER(pid), + __comp_pid); + if (found) { + if (g_list_first(list) == found) + return false; + return true; + } + } + } + + return false; +} + +void _app_group_reroute(int pid) +{ + GHashTableIter iter; + gpointer key; + gpointer value; + GList *list; + GList *found; + GList *before; + GList *after; + app_group_context_t *ac1; + app_group_context_t *ac2; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + list = (GList *)value; + if (list != NULL) { + found = g_list_find_custom(list, GINT_TO_POINTER(pid), + __comp_pid); + if (found) { + before = g_list_previous(found); + after = g_list_next(found); + if (before == NULL || after == NULL) + return; + + _D("reroute"); + ac1 = (app_group_context_t *)before->data; + ac2 = (app_group_context_t *)after->data; + + __attach_window(ac1->wid, ac2->wid); + break; + } + } + } +} + +int _app_group_get_leader_pid(int pid) +{ + GHashTableIter iter; + gpointer key; + gpointer value; + GList *list; + GList *found; + int lpid = -1; + int again = 0; + +repeat: + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + list = (GList *)value; + if (list != NULL) { + found = g_list_find_custom(list, GINT_TO_POINTER(pid), + __comp_pid); + if (found) { + lpid = GPOINTER_TO_INT(key); + break; + } + } + } + + if (lpid == -1 && dead_pid == pid) + lpid = focused_leader_pid; + + if (lpid == -1 && again == 0) { + pid = getpgid(pid); + again = 1; + goto repeat; + } + + return lpid; +} + +void _app_group_set_dead_pid(int pid) +{ + focused_leader_pid = _app_group_get_leader_pid(pid); + dead_pid = pid; + if (dead_pid == focused_leader_pid) { + focused_leader_pid = -1; + dead_pid = -1; + } +} + +int _app_group_get_status(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 ac->status; + + i = g_list_next(i); + } + } + return -1; +} + +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; + 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 = _app_status_find(pid); + pkgid = _app_status_get_pkgid(app_status); + _D("send group signal %d", pid); + aul_send_app_group_signal(lpid, pid, pkgid); + ac->group_sig = 1; + } + } else { + __set_fg_flag(pid, 0, force); + } + } +} + +int _app_group_set_status(int pid, int status, bool force) +{ + GHashTableIter iter; + gpointer key; + gpointer value; + GList *list; + GList *i; + app_group_context_t *ac; + GList *last; + app_group_context_t *last_ac; + int lpid; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + list = (GList *)value; + last = g_list_last(list); + last_ac = (app_group_context_t *)last->data; + lpid = GPOINTER_TO_INT(key); + i = g_list_first(list); + while (i != NULL) { + ac = (app_group_context_t *)i->data; + if (ac && ac->pid == pid) { + __set_status(ac, last_ac, lpid, pid, status, + force); + return 0; + } + i = g_list_next(i); + } + } + return -1; +} + +int _app_group_get_fg_flag(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 ac->fg; + + i = g_list_next(i); + } + } + + return 0; +} + +int _app_group_set_hint(int pid, bundle *kb) +{ + char *str_leader = NULL; + char *str_reroute = NULL; + GHashTableIter iter; + gpointer key; + gpointer value; + GList *list; + GList *i; + app_group_context_t *ac; + + if (kb == NULL) + return -1; + + bundle_get_str(kb, AUL_SVC_K_CAN_BE_LEADER, &str_leader); + bundle_get_str(kb, AUL_SVC_K_REROUTE, &str_reroute); + + 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) { + if (str_leader && !strcmp(str_leader, "true")) + ac->can_be_leader = 1; + if (str_reroute && !strcmp(str_reroute, "true")) + ac->reroute = 1; + return 0; + } + i = g_list_next(i); + } + } + + return -1; +} + +int _app_group_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) { + _W("found the second leader, lpid: %d, pid: %d", + lpid, ac->pid); + return ac->pid; + } + } + } + + return -1; +} + +void _app_group_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)); + } + } +} + +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; + + *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) { + _E("no caller pid"); + return -1; + } + + caller_pid = atoi(val); + *lpid = _app_group_get_leader_pid(caller_pid); + if (*lpid != -1) { + caller_wid = _app_group_get_window(caller_pid); + if (caller_wid == 0) { + _D("caller window wasn't ready"); + if (__can_be_leader(b)) + *can_attach = false; + else + *can_attach = true; + } + } else { + _E("no lpid"); + if (__can_be_leader(b)) + *can_attach = false; + else + return -1; + } + } + + return 0; +} + +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); + int can_shift = 0; + int recycle = 0; + const char *str; + + _D("app_group_start_app"); + + str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW); + if (str != NULL && strcmp(str, "true") == 0) + can_shift = 1; + + str = bundle_get_val(b, AUL_SVC_K_RECYCLE); + if (str != NULL && strcmp(str, "true") == 0) + recycle = 1; + + if (can_attach) + __group_add(lpid, pid, 0, mode, caller_pid, 0, recycle); + else + __group_add(pid, pid, 0, mode, caller_pid, can_shift, 0); + _app_group_set_hint(pid, b); +} + +int _app_group_find_singleton(const char *appid, int *found_pid, + int *found_lpid) +{ + GHashTableIter iter; + gpointer key = NULL; + gpointer value = NULL; + app_status_h app_status; + const char *target; + GList *list; + app_group_context_t *ac; + int singleton = APP_GROUP_LAUNCH_MODE_SINGLETON; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + list = (GList *)value; + while (list != NULL) { + ac = (app_group_context_t *)list->data; + if (ac && ac->launch_mode == singleton) { + app_status = _app_status_find(ac->pid); + target = _app_status_get_appid(app_status); + if (appid && target && !strcmp(appid, target)) { + *found_pid = ac->pid; + *found_lpid = GPOINTER_TO_INT(key); + return 0; + } + } + list = g_list_next(list); + } + } + + return -1; +} + +int _app_group_can_reroute(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 ac->reroute; + + i = g_list_next(i); + } + } + + return 0; +} + +void _app_group_lower(int pid, int *exit) +{ + app_group_context_t *ac; + GHashTableIter iter; + gpointer key; + gpointer value; + GList *list; + GList *i; + + if (_app_group_is_sub_app(pid)) { + if (__can_recycle(pid) && __can_reroute(pid)) { + ac = __get_context(pid); + if (ac) { + _app_group_reroute(pid); + + if (ac->wid != 0) + __detach_window(ac->wid); + + ac = __context_dup(ac); + __group_remove(pid); + if (ac) + __do_recycle(ac); + } + *exit = 0; + } else + *exit = 1; + return; + } + + *exit = 0; + 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) { + if (ac->can_shift) { + __detach_window(ac->wid); + ac->can_shift = 0; + __lower_window(ac->wid); + } + return; + } + i = g_list_next(i); + } + } +} + +static void __restart_app(app_group_context_t *ac, int pid, bundle *b) +{ + const char *pid_str; + int cwid; + + ac->caller_pid = __get_caller_pid(b); + + if (ac->can_shift) { + if (ac->wid != 0) + __detach_window(ac->wid); + ac->can_shift = 0; + } + + pid_str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW); + if (pid_str && !strcmp(pid_str, "true")) { + ac->can_shift = 1; + if (ac->wid != 0) { + if (ac->caller_pid > 0) { + cwid = _app_group_get_window(ac->caller_pid); + if (cwid != 0) + __attach_window(cwid, ac->wid); + else + _E("invalid caller wid"); + } else { + _E("invalid caller pid"); + } + } + } +} + +void _app_group_restart_app(int pid, bundle *b) +{ + GList *list; + GList *i; + GHashTableIter iter; + gpointer key; + gpointer value; + app_group_context_t *ac; + + if (b == NULL) + return; + + 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) { + __restart_app(ac, pid, b); + return; + } + i = g_list_next(i); + } + } +} + +int _app_group_find_pid_from_recycle_bin(const char *appid) +{ + app_group_context_t *ac; + 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 = _app_status_find(ac->pid); + appid_from_bin = _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; +} + +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) { + _E("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; +} + +int _app_group_get_next_caller_pid(int pid) +{ + GList *list; + GList *i; + GHashTableIter iter; + gpointer key; + gpointer value; + 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) { + i = g_list_next(i); + if (i == NULL) + return -1; + + ac = (app_group_context_t *)i->data; + return ac->caller_pid; + } + i = g_list_next(i); + } + } + + return -1; +} + +int _app_group_activate_below(int pid, const char *below_appid) +{ + app_group_context_t *context = __get_context(pid); + int wid; + int tpid; + GList *list; + GHashTableIter iter; + gpointer key; + gpointer value; + app_status_h app_status; + const char *appid; + + if (!context) { + _E("Invalid pid"); + return -1; + } + + if (context->wid == 0) { + _E("Caller wid was 0"); + return -1; + } + + if (!below_appid) { + _E("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 = _app_status_find(tpid); + appid = _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; + } + } + + _E("Failed to find available appid to move"); + return -1; +} + +int _app_group_activate_above(int pid, const char *above_appid) +{ + app_group_context_t *context = __get_context(pid); + int wid; + int tpid; + GList *list; + GHashTableIter iter; + gpointer key; + gpointer value; + app_status_h app_status; + const char *appid; + + if (!context) { + _E("Invalid pid"); + return -1; + } + + if (context->wid == 0) { + _E("Caller wid was 0"); + return -1; + } + + if (!above_appid) { + _E("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 = _app_status_find(tpid); + appid = _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; + } + } + + _E("Failed to find available appid to move"); + return -1; +} + +int _app_group_attach(const char *parent_appid, const char *child_appid, + uid_t uid) +{ + app_status_h status; + int ppid; + int cpid; + int pwid; + int cwid; + + status = _app_status_find_by_appid(parent_appid, uid); + if (!status) { + _E("parent app is not running %s", parent_appid); + return -1; + } + + ppid = _app_status_get_pid(status); + status = _app_status_find_by_appid(child_appid, uid); + if (!status) { + _E("child app is not running %s", child_appid); + return -1; + } + + pwid = _app_group_get_window(ppid); + if (pwid == 0) { + _E("window wasn't ready - ppid(%d)", ppid); + return -1; + } + + cpid = _app_status_get_pid(status); + cwid = _app_group_get_window(cpid); + if (cwid == 0) { + _E("window wasn't ready - cpid(%d)", cpid); + return -1; + } + + __attach_window(pwid, cwid); + + return 0; +} + +int _app_group_detach(const char *child_appid, uid_t uid) +{ + app_status_h status; + int cpid; + int cwid; + + status = _app_status_find_by_appid(child_appid, uid); + if (!status) { + _E("child app is not running %s", child_appid); + return -1; + } + + cpid = _app_status_get_pid(status); + cwid = _app_group_get_window(cpid); + if (cwid == 0) { + _E("window wasn't ready : %d", cwid); + return -1; + } + + __detach_window(cwid); + + return 0; +} + +int _app_group_init(void) +{ + _D("app group init"); + _wayland_add_registry_listener(®istry_listener, NULL); + app_group_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, NULL); + if (app_group_hash == NULL) { + _E("Failed to create app group hash"); + return -1; + } + + return 0; +} + +void _app_group_fini(void) +{ + _D("app group fini"); + /* TODO: Destroy app group info */ +} + diff --git a/src/amd_app_property.c b/src/amd_app_property.c new file mode 100644 index 0000000..ec00f0c --- /dev/null +++ b/src/amd_app_property.c @@ -0,0 +1,741 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_app_property.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(%d)", + 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(%d)", 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; + + 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; + } + } + + if (g_list_find_custom(prop->metadata_list, entity, __comp_metadata_list)) + 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)); +} + +int _app_property_init(void) +{ + _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; + } + + return 0; +} + +void _app_property_fini(void) +{ + _D("app property fini"); + + if (user_prop_table) + g_hash_table_destroy(user_prop_table); +} + +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)); +} + +const char *_app_property_cache_get(app_property_h app_property, const char *checksum) +{ + const char *appid; + + if (!app_property || !checksum) + return NULL; + + appid = g_hash_table_lookup(app_property->appid_cache_table, checksum); + + return appid; +} + +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; +} + + diff --git a/src/amd_app_status.c b/src/amd_app_status.c new file mode 100644 index 0000000..22ce370 --- /dev/null +++ b/src/amd_app_status.c @@ -0,0 +1,1840 @@ +/* + * Copyright (c) 2000 - 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amd_app_status.h" +#include "amd_appinfo.h" +#include "amd_request.h" +#include "amd_launch.h" +#include "amd_util.h" +#include "amd_app_group.h" +#include "amd_input.h" +#include "amd_suspend.h" +#include "amd_socket.h" +#include "amd_share.h" +#include "amd_extractor.h" +#include "amd_app_com.h" +#include "amd_widget.h" +#include "amd_screen_connector.h" +#include "amd_cooldown.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; + GList *shared_info_list; + bool bg_launch; + bool socket_exists; + bool starting; + bool is_exit_notified; + bool debug_mode; + guint timer; +}; + +struct fault_app_s { + int pid; + int uid; + char *appid; + char *pkgid; + int type; +}; + +static GHashTable *oom_app_table; +static GHashTable *pkg_update_app_table; +static GSList *app_status_list; +static GHashTable *pkg_status_table; +static int limit_bg_uiapps; +static char *home_appid; +static GHashTable *__wd_table; + +int _app_status_set_is_exit_notified(app_status_h app_status, bool is_exit_notified) +{ + if (app_status == NULL) + return -1; + + app_status->is_exit_notified = is_exit_notified; + + return 0; +} + +bool _app_status_get_is_exit_notified(app_status_h app_status) +{ + if (app_status == NULL) + return false; + + return app_status->is_exit_notified; +} + +static void __send_fault_dead_signal(int pid, int uid, const char *appid, + int type, bool is_exit_notified) +{ + char *endpoint = NULL; + char sender_pid_str[MAX_PID_STR_BUFSZ]; + bundle *kb; + + if (type == AT_WATCH_APP) + endpoint = "watch.dead"; + + if (endpoint == NULL) + return; + + kb = bundle_create(); + if (!kb) { + _E("cannot create bundle out of memory"); + return; + } + + _D("send pid %d uid %d appid %s type %d is_exit_notified %d", + pid, uid, appid, type, is_exit_notified); + + snprintf(sender_pid_str, MAX_PID_STR_BUFSZ, "%d", pid); + bundle_add(kb, AUL_K_APPID, appid); + bundle_add(kb, AUL_K_PID, sender_pid_str); + bundle_add(kb, AUL_K_IS_FAULT, (is_exit_notified == true) ? "false" : "true"); + + _app_com_send(endpoint, getpgid(pid), kb, uid); +} + +void _app_status_fault_recovery(int pid, int uid, const char *pkgid, + const char *appid, int type, bool is_exit_notified) +{ + struct fault_app_s *app_info; + + if (_util_check_oom()) { + app_info = + g_hash_table_lookup( + oom_app_table, + appid); + if (app_info == NULL) { + app_info = (struct fault_app_s *) + calloc(1, sizeof(struct fault_app_s)); + app_info->appid = strdup(appid); + app_info->pkgid = strdup(pkgid); + app_info->pid = pid; + app_info->uid = uid; + app_info->type = type; + g_hash_table_insert( + oom_app_table, + app_info->appid, + app_info); + } + } else if (_appinfo_is_pkg_updating(pkgid)) { + app_info = + g_hash_table_lookup( + pkg_update_app_table, + appid); + if (app_info == NULL) { + app_info = (struct fault_app_s *) + calloc(1, sizeof(struct fault_app_s)); + app_info->appid = strdup(appid); + app_info->pkgid = strdup(pkgid); + app_info->pid = pid; + app_info->uid = uid; + app_info->type = type; + g_hash_table_insert( + pkg_update_app_table, + app_info->pkgid, + app_info); + } + } else { + __send_fault_dead_signal(pid, uid, appid, type, is_exit_notified); + } +} + +static void __destroy_fault_app_info(gpointer data) +{ + struct fault_app_s *info = + (struct fault_app_s *)data; + + if (info == NULL) + return; + if (info->appid) + free(info->appid); + if (info->pkgid) + free(info->pkgid); + + free(info); +} + +void _app_status_send_fault_dead_for_oom_apps(void) +{ + GHashTableIter iter; + gpointer key, value; + struct fault_app_s *info; + + g_hash_table_iter_init(&iter, oom_app_table); + while (g_hash_table_iter_next(&iter, &key, &value)) { + info = (struct fault_app_s *)value; + __send_fault_dead_signal(info->pid, info->uid, info->appid, + info->type, false); + } + g_hash_table_remove_all(oom_app_table); + +} + +void _app_status_send_fault_dead_for_update_app(const char *pkgid) +{ + struct fault_app_s *info; + + info = g_hash_table_lookup(pkg_update_app_table, pkgid); + if (info != NULL) { + __send_fault_dead_signal(info->pid, info->uid, info->appid, + info->type, false); + g_hash_table_remove(pkg_update_app_table, pkgid); + } +} + +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 gint __compare_app_status_for_sorting(gconstpointer p1, gconstpointer p2) +{ + struct app_status_s *app_status1 = (struct app_status_s *)p1; + struct app_status_s *app_status2 = (struct app_status_s *)p2; + int app_group_cnt1; + int app_group_cnt2; + int *app_group_pids1; + int *app_group_pids2; + + if (app_status1->app_type != AT_UI_APP || + app_status2->app_type != AT_UI_APP) + return 0; + + if (app_status1->timestamp > app_status2->timestamp) + return 1; + else if (app_status1->timestamp < app_status2->timestamp) + return -1; + + _app_group_get_group_pids(app_status1->leader_pid, &app_group_cnt1, + &app_group_pids1); + _app_group_get_group_pids(app_status2->leader_pid, &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; + + if (app_status1->fg_count > app_status2->fg_count) + return 1; + else if (app_status1->fg_count < app_status2->fg_count) + return -1; + + return 0; +} + +static void __check_running_uiapp_list(void) +{ + int len; + int n; + + len = __get_managed_uiapp_cnt(); + if (len <= 0) + return; + + n = len - limit_bg_uiapps; + if (n <= 0) + return; + + app_status_list = g_slist_sort(app_status_list, + (GCompareFunc)__compare_app_status_for_sorting); + __cleanup_bg_uiapps(n); +} + +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 __remove_all_shared_info(struct app_status_s *app_status) +{ + GList *list; + shared_info_t *shared_info; + + if (!app_status || !app_status->shared_info_list) + return; + + list = app_status->shared_info_list; + while (list) { + shared_info = (shared_info_t *)list->data; + if (shared_info) { + if (shared_info->owner_appid) + free(shared_info->owner_appid); + free(shared_info); + } + list = g_list_next(list); + } + + g_list_free(app_status->shared_info_list); + app_status->shared_info_list = NULL; +} + +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; + + if (app_status->app_type == AT_WIDGET_APP) + _widget_cleanup(app_status->pid, app_status->uid); + + __remove_all_shared_info(app_status); + + 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->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) +{ + 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; + if (app_status->app_type == AT_UI_APP) + app_status->leader_pid = _app_group_get_leader_pid(pid); + + 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->is_exit_notified = false; + + return 0; +} + +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); + if (r < 0) { + __destroy_app_status(app_status); + return -1; + } + + 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); +#ifdef TIZEN_FEATURE_BLOCK_INPUT + _input_unlock(); +#endif /* TIZEN_FEATURE_BLOCK_INPUT */ + + 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) { + _screen_connector_remove_app_screen_v2(app_status->pid, + app_status->uid); + if (!app_status->debug_mode) { + app_status->timer = g_timeout_add_seconds(5, + __terminate_timer_cb, + GINT_TO_POINTER(app_status->pid)); + } + aul_send_app_terminate_request_signal(app_status->pid, + NULL, NULL, NULL); + } + + __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); + + if (update_group_info && status != STATUS_DYING) + _app_group_set_status(app_status->pid, app_status->status, force); + + 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; +} + +int _app_status_add_shared_info(app_status_h app_status, shared_info_t *info) +{ + if (app_status == NULL || info == NULL) + return -1; + + app_status->shared_info_list = g_list_append( + app_status->shared_info_list, info); + + return 0; +} + +int _app_status_clear_shared_info_list(app_status_h app_status) +{ + if (app_status == NULL) + return -1; + + __remove_all_shared_info(app_status); + + return 0; +} + +GList *_app_status_get_shared_info_list(app_status_h app_status) +{ + return app_status->shared_info_list; +} + +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 = NULL; + + 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; + int 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 = (intptr_t)_appinfo_get_value(ai, + AIT_BG_CATEGORY); + if (!bg_allowed) { + send_event_to_svc_core(svc_status->pid, uid); + if (suspend) + _suspend_add_timer(svc_status->pid, ai); + 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; + int 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 = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY); + if (!bg_allowed) { + send_event_to_svc_core(app_status->pid, uid); + _suspend_add_timer(app_status->pid, ai); + } + } +} + +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; +} + +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; + int caller_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); + + instance_id = _app_status_get_instance_id(app_status); + if (instance_id == NULL) + instance_id = _app_status_get_appid(app_status); + _screen_connector_remove_app_screen_v2(pid, uid); + _screen_connector_remove_screen_viewer_v2(pid, uid); + + __terminate_widget_apps_by_org_caller(pid, uid); + _extractor_unmount(pid, _extractor_mountable_get_tep_paths); + _extractor_unmount(pid, _extractor_mountable_get_tpk_paths); + _app_com_client_remove(pid); + if (_app_group_is_leader_pid(pid)) { + _W("app_group_leader_app, pid: %d", pid); + if (_app_group_find_second_leader(pid) == -1) { + _app_group_clear_top(pid, uid); + _app_group_set_dead_pid(pid); + _app_group_remove(pid); + } else { + _app_group_remove_leader_pid(pid); + } + } else if (_app_group_is_sub_app(pid)) { + _W("app_group_sub_app, pid: %d", pid); + caller_pid = _app_group_get_next_caller_pid(pid); + if (_app_group_can_reroute(pid) + || (caller_pid > 0 && caller_pid != pid)) { + _W("app_group reroute"); + _app_group_reroute(pid); + } else { + _W("app_group clear top"); + _app_group_clear_top(pid, uid); + } + _app_group_set_dead_pid(pid); + _app_group_remove(pid); + } + + _launch_remove_fgmgr(pid); + _suspend_remove_proc(pid); + _app_group_remove_from_recycle_bin(pid); + _temporary_permission_drop(pid, uid); + _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; +} + +static bool __dir_monitor_cb(const char *event_name, void *data) +{ + char *path = (char *)data; + char *str = basename(path); + uid_t uid; + int wd; + + if (event_name == NULL || str == NULL) + return true; + + if (strcmp(event_name, str) == 0) { + wd = _inotify_add_watch(path, IN_CREATE, __socket_monitor_cb, + NULL); + uid = strtol(event_name, NULL, 10); + g_hash_table_insert(__wd_table, GUINT_TO_POINTER(uid), + GINT_TO_POINTER(wd)); + free(path); + return false; + } + + return true; +} + +int _app_status_usr_init(uid_t uid) +{ + int wd; + char buf[PATH_MAX]; + char *path; + + 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); + if (access(buf, F_OK) == 0) { + 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)); + } else { + path = strdup(buf); + if (path == NULL) { + _E("Out of memory"); + return -1; + } + + _inotify_add_watch("/run/aul/apps", IN_CREATE, + __dir_monitor_cb, path); + } + + 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) + 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 void __remove_inotify_watch(gpointer data) +{ + int wd = GPOINTER_TO_INT(data); + + if (wd <= 0) + return; + + _inotify_rm_watch(wd); +} + +int _app_status_init(void) +{ + int ret; + + __wd_table = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, __remove_inotify_watch); + if (__wd_table == NULL) { + _E("Failed to create wd hash table"); + 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); + } + + oom_app_table = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, __destroy_fault_app_info); + pkg_update_app_table = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, __destroy_fault_app_info); + + _cooldown_init(); + 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); + + _cooldown_fini(); + + g_hash_table_destroy(oom_app_table); + g_hash_table_destroy(pkg_update_app_table); + + return 0; +} diff --git a/src/amd_appinfo.c b/src/amd_appinfo.c new file mode 100644 index 0000000..9022b8a --- /dev/null +++ b/src/amd_appinfo.c @@ -0,0 +1,1973 @@ +/* + * Copyright (c) 2015 - 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_login_monitor.h" +#include "amd_widget.h" + +static pkgmgr_client *pc; +static GHashTable *user_tbl; +static GHashTable *pkg_pending; +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; +}; + +static GList *app_event_list; + +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; + +enum _background_category { + _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 +}; + +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); + + 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); + + 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"); + + 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"); + + 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"); + + 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"); + + 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); + + 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"); + + return 0; +} + +static int __appinfo_add_status(const pkgmgrinfo_appinfo_h handle, + struct appinfo *info, void *data) +{ + info->val[AIT_STATUS] = strdup("installed"); + + 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"); + + 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); + + return 0; +} + +static int __appinfo_add_tep(const pkgmgrinfo_appinfo_h handle, + struct appinfo *info, void *data) +{ + int ret; + char *tep_name = NULL; + + ret = pkgmgrinfo_appinfo_get_tep_name(handle, &tep_name); + if (ret != PMINFO_R_OK) { + info->val[AIT_TEP] = NULL; + } else { + if (tep_name && strlen(tep_name) > 0) + info->val[AIT_TEP] = strdup(tep_name); + else + info->val[AIT_TEP] = NULL; + } + + return 0; +} + +static int __appinfo_add_mountable_pkg(const pkgmgrinfo_appinfo_h handle, + struct appinfo *info, void *data) +{ + int ret; + char *tpk_name = NULL; + + ret = pkgmgrinfo_appinfo_get_zip_mount_file(handle, &tpk_name); + if (ret != PMINFO_R_OK) { + info->val[AIT_MOUNTABLE_PKG] = NULL; + } else { + if (tpk_name && strlen(tpk_name) > 0) + info->val[AIT_MOUNTABLE_PKG] = strdup(tpk_name); + else + info->val[AIT_MOUNTABLE_PKG] = NULL; + } + + 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"); + } + + 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"); + + 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"); + + return 0; +} + +static int __appinfo_add_effective_appid(const pkgmgrinfo_appinfo_h handle, + struct appinfo *info, void *data) +{ + int ret; + char *effective_appid = NULL; + + ret = pkgmgrinfo_appinfo_get_effective_appid(handle, &effective_appid); + if (ret != PMINFO_R_OK) { + info->val[AIT_EFFECTIVE_APPID] = NULL; + } else { + if (effective_appid && strlen(effective_appid) > 0) { + info->val[AIT_EFFECTIVE_APPID] = + strdup(effective_appid); + } + } + + 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"); + + 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); + + 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; + } + + info->val[AIT_ROOT_PATH] = path ? strdup(path) : NULL; + + 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); + splash_image->type = strdup(type); + splash_image->indicatordisplay = strdup(indicatordisplay); + splash_image->color_depth = strdup(color_depth); + key = strdup(operation); + + 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, g_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, g_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); + + 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"); + + 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 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 + }, + +}; + +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); + + 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) { + _E("Failed to find appinfo(%s)", appid); + return -1; + } + + if (c->val[AIT_STATUS] && strcmp(c->val[AIT_STATUS], "restart") == 0) + restart = true; + else + restart = false; + + for (i = AIT_START; i < AIT_MAX; i++) { + if (appinfo_table[i].destructor && c->val[i]) + appinfo_table[i].destructor(c->val[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]); + _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"); + _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, value; + uid_t *uids = NULL; + + 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)) { + struct appinfo *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, 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); + } + } + } + + return; +} + +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); + _widget_send_dead_signal_for_update_widget(pkgid); + _app_status_send_fault_dead_for_update_app(pkgid); + } + + 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 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; + int old; + struct app_event_info *ei; + uid_t *uids = NULL; + int r; + int i; + struct user_appinfo *info; + pkgmgrinfo_appinfo_h handle; + + _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")) { + if (!strcasecmp(val, "enable_global_app_for_uid") || + !strcasecmp(val, "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, target_uid); + } else if (!strcasecmp(val, "disable_global_app_for_uid") || + !strcasecmp(val, "disable_app")) { + __add_app_event_info(req_id, AIT_ENABLEMENT, target_uid); + } else if (!strcasecmp(val, "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, target_uid); + } + } else if (!strcasecmp(val, "disable_app_splash_screen")) { + if (ai) + __add_app_event_info(req_id, AIT_SPLASH_SCREEN_DISPLAY, target_uid); + } + } else if (!strcasecmp(key, "end")) { + ei = __find_app_event_info(req_id, target_uid); + if (ei == NULL) + continue; + + if (!strcasecmp(val, "ok")) { + if (ei->type == AIT_ENABLEMENT || + 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 (ei->type == AIT_ENABLEMENT) { + info = __find_user_appinfo(target_uid); + if (info == NULL) { + _E("load appinfo for uid %d failed", target_uid); + __remove_app_event_info(ei); + continue; + } + + r = pkgmgrinfo_appinfo_get_usr_appinfo(appid, target_uid, &handle); + if (r != PMINFO_R_OK) { + _E("get appinfo failed: %s", appid); + __remove_app_event_info(ei); + continue; + } + + _D("add the new appinfo"); + __insert_appinfo(handle, info); + pkgmgrinfo_appinfo_destroy_appinfo(handle); + __remove_app_event_info(ei); + continue; + } + + if (ei->type == AIT_ENABLEMENT && + !(old & APP_ENABLEMENT_MASK_ACTIVE)) { + _E("terminate apps: %s", appid); + _app_status_terminate_apps(appid, + target_uid); + } else if (ei->type == AIT_ENABLEMENT && + (old & APP_ENABLEMENT_MASK_ACTIVE)) { + _launch_start_onboot_app_local( + target_uid, appid, ai); + } + } + } else if (!strcasecmp(val, "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); + } + } + + 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); +} + +int _appinfo_init(void) +{ + FILE *fp; + char buf[4096] = {0,}; + char *tmp; + char err_buf[1024]; + + fp = fopen("/proc/cmdline", "r"); + if (fp == NULL) { + _E("appinfo init failed: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + 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); + + 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; +} + +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); +} + +void _appinfo_reload(void) +{ + g_hash_table_foreach(user_tbl, __reload_appinfo, NULL); +} + +const char *_appinfo_get_value(const struct appinfo *c, enum appinfo_type type) +{ + char err_buf[1024]; + + if (!c) { + errno = EINVAL; + _E("appinfo get value: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + 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) +{ + char err_buf[1024]; + + if (!c) { + errno = EINVAL; + _E("appinfo get value: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + 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) +{ + char err_buf[1024]; + + if (!c) { + errno = EINVAL; + _E("appinfo get value: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + 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) +{ + char err_buf[1024] = {0, }; + + if (!c || type < AIT_START || type >= AIT_MAX + || c->val[type] == NULL) { + errno = EINVAL; + _E("appinfo get boolean: %s", strerror_r(errno, err_buf, + sizeof(err_buf))); + 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 { + errno = EINVAL; + _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) { + errno = EINVAL; + _E("appinfo is NULL, type: %d, val %s", type, val); + 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); + + return 0; +} + +int _appinfo_set_ptr_value(struct appinfo *c, enum appinfo_type type, void *val) +{ + if (!c || !val) { + errno = EINVAL; + _E("appinfo is NULL, type: %d, val %p", type, val); + 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) { + errno = EINVAL; + _E("appinfo is NULL, type: %d, val %d", type, val); + return -1; + } + + if (type < AIT_START || type >= AIT_MAX) + return -1; + + _D("%s : %p : %p", c->val[AIT_NAME], c->val[type], val); + + c->val[type] = (char *)GINT_TO_POINTER(val); + return 0; +} + +struct _cbinfo { + appinfo_iter_callback cb; + void *cb_data; +}; + +static void __iter_cb(gpointer key, gpointer value, gpointer user_data) +{ + struct _cbinfo *cbi = user_data; + + if (cbi == NULL) + return; + + cbi->cb(cbi->cb_data, key, value); +} + +void _appinfo_foreach(uid_t uid, appinfo_iter_callback cb, void *user_data) +{ + struct user_appinfo *info; + struct _cbinfo cbi; + char err_buf[1024]; + + info = __find_user_appinfo(uid); + if (info == NULL) + return; + + if (!cb) { + errno = EINVAL; + _E("appinfo foreach: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + return; + } + + cbi.cb = cb; + cbi.cb_data = user_data; + + g_hash_table_foreach(info->tbl, __iter_cb, &cbi); +} + +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"); + return; + } + + __remove_user_appinfo(uid); + _D("unloaded appinfo table for uid(%d)", uid); +} + +bool _appinfo_is_pkg_updating(const char *pkgid) +{ + char *op; + + if (pkg_pending == NULL) + return false; + + op = g_hash_table_lookup(pkg_pending, pkgid); + if (op != NULL && !strcasecmp(op, "update")) + return true; + + return false; +} diff --git a/src/amd_cooldown.c b/src/amd_cooldown.c new file mode 100644 index 0000000..4de722b --- /dev/null +++ b/src/amd_cooldown.c @@ -0,0 +1,164 @@ +/* + * 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 +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_app_status.h" +#include "amd_appinfo.h" +#include "amd_launch.h" +#include "amd_login_monitor.h" +#include "amd_signal.h" +#include "amd_cooldown.h" + +static int cooldown_status; + +static void __cooldown_limitaction(app_status_h app_status, void *data) +{ + const struct appinfo *ai; + const char *taskmanage; + const char *cooldown; + const char *appid; + int app_type; + uid_t uid; + + if (_app_status_is_home_app(app_status)) + return; + + app_type = _app_status_get_app_type(app_status); + if (app_type == AT_WIDGET_APP || app_type == AT_WATCH_APP) + return; + + uid = _app_status_get_uid(app_status); + appid = _app_status_get_appid(app_status); + ai = _appinfo_find(uid, appid); + if (ai == NULL) + return; + + cooldown = _appinfo_get_value(ai, AIT_COOLDOWN); + if (cooldown && strcmp(cooldown, "true") != 0) { + if (app_type == AT_UI_APP) { + taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE); + if (taskmanage && strcmp(taskmanage, "true") != 0) + return; + } + + _app_status_terminate_apps(appid, uid); + } +} + +static void __cooldown_release(void) +{ + uid_state state; + uid_t *uids; + int r; + int i; + + r = _login_monitor_get_uids(&uids); + if (r <= 0) + return; + + for (i = 0; i < r; ++i) { + state = _login_monitor_get_uid_state(uids[i]); + if (state == UID_STATE_ONLINE || state == UID_STATE_ACTIVE) + _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; + _app_status_foreach_running_appinfo(__cooldown_limitaction, + NULL); + } else if (strcmp(status, COOLDOWN_STATUS_RELEASE) == 0 && + cooldown_status != COOLDOWN_RELEASE) { + cooldown_status = COOLDOWN_RELEASE; + __cooldown_release(); + } + + return 0; +} + +int _cooldown_get_status(void) +{ + return cooldown_status; +} + +int _cooldown_check_mode(const struct appinfo *ai) +{ + const char *taskmanage; + const char *cooldown; + const char *comptype; + + if (cooldown_status != COOLDOWN_LIMIT) + return 0; + + cooldown = _appinfo_get_value(ai, AIT_COOLDOWN); + if (cooldown && strcmp(cooldown, "true") == 0) + return 0; + + comptype = _appinfo_get_value(ai, 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 = _appinfo_get_value(ai, AIT_TASKMANAGE); + if (taskmanage && strcmp(taskmanage, "false") == 0) + return 0; + } + + _W("Cannot launch this app in COOLDOWN mode"); + return -1; +} + +static int __register_cooldown_signal(void *data) +{ + return aul_listen_cooldown_signal(__cooldown_signal_cb, data); +} + +int _cooldown_init(void) +{ + int r; + + _D("cooldown init"); + + r = __register_cooldown_signal(NULL); + if (r < 0) { + _W("Failed to register cooldown signal"); + _signal_add_initializer(__register_cooldown_signal, NULL); + } + + return 0; +} + +void _cooldown_fini(void) +{ + _D("cooldown fini"); + aul_listen_cooldown_signal(NULL, NULL); +} diff --git a/src/amd_cynara.c b/src/amd_cynara.c new file mode 100644 index 0000000..e90d874 --- /dev/null +++ b/src/amd_cynara.c @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2015 - 2016 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_app_status.h" +#include "amd_widget.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" + +static cynara *r_cynara; + +struct caller_info { + char *user; + char *client; + char *session; +}; + +typedef int (*checker_func)(struct caller_info *info, request_h req, + void *data); + +struct checker_info { + int cmd; + checker_func checker; + void *data; +}; + +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; + else if (!strcmp(operation, AUL_SVC_OPERATION_LAUNCH_WIDGET)) + return PRIVILEGE_WIDGET_VIEWER; + + return NULL; +} + +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); +} + +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 int __check_privilege(struct caller_info *info, const char *privilege) +{ + int ret; + char buf[MAX_LOCAL_BUFSZ]; + + ret = cynara_check(r_cynara, info->client, info->session, info->user, + privilege); + switch (ret) { + case CYNARA_API_ACCESS_ALLOWED: + _D("%s(%s) from user %s privilege %s allowed.", info->client, + info->session, info->user, privilege); + ret = 0; + break; + case CYNARA_API_ACCESS_DENIED: + _E("%s(%s) from user %s privilege %s denied.", info->client, + info->session, info->user, privilege); + ret = -1; + break; + default: + cynara_strerror(ret, buf, MAX_LOCAL_BUFSZ); + _E("cynara_check failed: %s", buf); + ret = -1; + break; + } + + return ret; +} + +static int __simple_checker(struct caller_info *info, request_h req, void *data) +{ + return __check_privilege(info, (const char *)data); +} + +static int __widget_viewer_checker(struct caller_info *info, request_h req, + void *data) +{ + char *appid = NULL; + const char *apptype; + struct appinfo *appinfo; + bundle *appcontrol = _request_get_bundle(req); + + if (!appcontrol) { + _E("wrong argument"); + return -1; + } + + bundle_get_str(appcontrol, AUL_K_APPID, &appid); + if (!appid) { + _E("can not resolve appid. request denied."); + return -1; + } + + appinfo = _appinfo_find(_request_get_target_uid(req), appid); + if (!appinfo) { + _E("can not resolve appinfo of %s. request denied.", appid); + return -1; + } + + apptype = _appinfo_get_value(appinfo, AIT_COMPTYPE); + if (!apptype) { + _E("can not resolve apptype of %s. request denied.", appid); + return -1; + } + + if (!strcmp(apptype, APP_TYPE_WIDGET) || + !strcmp(apptype, APP_TYPE_WATCH)) + return __check_privilege(info, PRIVILEGE_WIDGET_VIEWER); + + _E("illegal app type of request: %s - " \ + "only widget or watch apps are allowed", apptype); + + return -1; +} + +static int __app_term_by_pid_async_checker(struct caller_info *info, + request_h req, void *data) +{ + int pid; + char *term_pid; + bool is_widget = false; + bundle *kb; + + kb = _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); + is_widget = _widget_exist(pid, _request_get_target_uid(req)); + + if (is_widget) + return __check_privilege(info, PRIVILEGE_WIDGET_VIEWER); + + return __simple_checker(info, req, data); +} + +static int __appcontrol_checker(struct caller_info *info, request_h req, + void *data) +{ + bundle *appcontrol; + const char *op_priv = NULL; + char *op = NULL; + const char *below; + const char *syspopup; + int ret; + + appcontrol = _request_get_bundle(req); + if (appcontrol == NULL) + return 0; + + 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) { + if (!strcmp(op_priv, PRIVILEGE_WIDGET_VIEWER)) + return __widget_viewer_checker(info, req, data); + + ret = __check_privilege(info, op_priv); + if (ret < 0) + return ret; + } + + syspopup = bundle_get_val(appcontrol, SYSPOPUP_NAME); + below = bundle_get_val(appcontrol, AUL_SVC_K_RELOCATE_BELOW); + if (below || syspopup) { + ret = __check_privilege(info, PRIVILEGE_PLATFORM); + if (ret < 0) + return ret; + } + + return __check_privilege(info, PRIVILEGE_APPMANAGER_LAUNCH); +} + +static int __com_create_checker(struct caller_info *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; /* non-privileged */ + + return __check_privilege(info, privilege); +} + +static int __com_join_checker(struct caller_info *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; /* non-privileged */ + + return __check_privilege(info, privilege); +} + +static int __label_checker(struct caller_info *info, request_h req, + void *data) +{ + if (strcmp(info->client, "System::Privileged") == 0) + return 0; + + return -1; +} + +static int __screen_connector_checker(struct caller_info *info, request_h req, + void *data) +{ + int ret; + bundle *b = _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 = __check_privilege(info, PRIVILEGE_PLATFORM); + else + ret = __check_privilege(info, PRIVILEGE_WIDGET_VIEWER); + + return ret; +} + +static struct checker_info checker_table[] = { + { + .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 = __simple_checker, + .data = PRIVILEGE_APPMANAGER_KILL + }, + { + .cmd = APP_TERM_BY_PID_ASYNC, + .checker = __app_term_by_pid_async_checker, + .data = PRIVILEGE_APPMANAGER_KILL + }, + { + .cmd = APP_TERM_BY_PID, + .checker = __simple_checker, + .data = PRIVILEGE_APPMANAGER_KILL + }, + { + .cmd = APP_KILL_BY_PID, + .checker = __simple_checker, + .data = PRIVILEGE_APPMANAGER_KILL + }, + { + .cmd = APP_TERM_BGAPP_BY_PID, + .checker = __simple_checker, + .data = PRIVILEGE_APPMANAGER_KILL_BGAPP + }, + { + .cmd = APP_COM_JOIN, + .checker = __com_create_checker, + .data = NULL + }, + { + .cmd = APP_COM_CREATE, + .checker = __com_join_checker, + .data = NULL + }, + { + .cmd = APP_SET_APP_CONTROL_DEFAULT_APP, + .checker = __simple_checker, + .data = PRIVILEGE_SYSTEM_SETTING + }, + { + .cmd = APP_UNSET_APP_CONTROL_DEFAULT_APP, + .checker = __simple_checker, + .data = PRIVILEGE_SYSTEM_SETTING + }, + { + .cmd = APP_START_ASYNC, + .checker = __appcontrol_checker, + .data = NULL + }, + { + .cmd = APP_TERM_BY_PID_SYNC, + .checker = __simple_checker, + .data = PRIVILEGE_APPMANAGER_KILL + }, + { + .cmd = APP_TERM_BY_PID_SYNC_WITHOUT_RESTART, + .checker = __simple_checker, + .data = PRIVILEGE_APPMANAGER_KILL + }, + { + .cmd = APP_UPDATE_RUA_STAT, + .checker = __simple_checker, + .data = PRIVILEGE_PLATFORM + }, + { + .cmd = APP_ADD_HISTORY, + .checker = __simple_checker, + .data = PRIVILEGE_PLATFORM + }, + { + .cmd = APP_REMOVE_HISTORY, + .checker = __simple_checker, + .data = PRIVILEGE_PLATFORM + }, + { + .cmd = APP_SET_ALIAS_APPID, + .checker = __simple_checker, + .data = PRIVILEGE_SYSTEM_SETTING + }, + { + .cmd = APP_UNSET_ALIAS_APPID, + .checker = __simple_checker, + .data = PRIVILEGE_SYSTEM_SETTING + }, + { + .cmd = APP_ENABLE_ALIAS_INFO, + .checker = __simple_checker, + .data = PRIVILEGE_SYSTEM_SETTING + }, + { + .cmd = APP_DISABLE_ALIAS_INFO, + .checker = __simple_checker, + .data = PRIVILEGE_SYSTEM_SETTING + }, + { + .cmd = LAUNCHPAD_LAUNCH_SIGNAL, + .checker = __label_checker, + .data = NULL + }, + { + .cmd = LAUNCHPAD_DEAD_SIGNAL, + .checker = __label_checker, + .data = NULL + }, + { + .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 = __simple_checker, + .data = PRIVILEGE_PLATFORM + }, + { + .cmd = APP_WINDOW_ATTACH, + .checker = __simple_checker, + .data = PRIVILEGE_PLATFORM + }, + { + .cmd = APP_WINDOW_DETACH, + .checker = __simple_checker, + .data = PRIVILEGE_PLATFORM + }, + { + .cmd = APP_START_RES_ASYNC, + .checker = __appcontrol_checker, + .data = NULL + }, + { + .cmd = WIDGET_RUNNING_INFO, + .checker = __simple_checker, + .data = PRIVILEGE_PLATFORM + } +}; + +static int checker_len = sizeof(checker_table) / sizeof(struct checker_info); + +static int __check_privilege_by_checker(request_h req, struct caller_info *info) +{ + int i; + int ret; + + for (i = 0; i < checker_len; i++) { + if (checker_table[i].cmd == _request_get_cmd(req)) { + ret = checker_table[i].checker(info, req, + checker_table[i].data); + return ret; + } + } + + return 0; +} + +static int __check_command(int cmd) +{ + int i; + + for (i = 0; i < checker_len; i++) { + if (checker_table[i].cmd == cmd) + return 1; + } + + return 0; +} + +int _cynara_check_privilege(request_h req) +{ + int r; + struct caller_info info = {NULL, NULL, NULL}; + + if (!__check_command(_request_get_cmd(req))) + return 0; + + r = __get_caller_info_from_cynara(_request_get_fd(req), &info); + if (r < 0) { + _E("Failed to get caller info"); + __destroy_caller_info(&info); + return -1; + } + + r = __check_privilege_by_checker(req, &info); + + __destroy_caller_info(&info); + + return r; +} + +int _cynara_init(void) +{ + int ret; + + ret = cynara_initialize(&r_cynara, NULL); + if (ret != CYNARA_API_SUCCESS) { + _E("cynara initialize failed."); + return ret; + } + + return 0; +} + +void _cynara_finish(void) +{ + if (r_cynara == NULL) + return; + + cynara_finish(r_cynara); + r_cynara = NULL; +} + diff --git a/src/amd_extractor.c b/src/amd_extractor.c new file mode 100644 index 0000000..c9b4427 --- /dev/null +++ b/src/amd_extractor.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2016 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "amd_util.h" +#include "amd_signal.h" +#include "amd_app_status.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) + +static GHashTable *mount_point_hash; + +static const char *__get_app_root_path(const struct appinfo *ai) +{ + const char *path_app_root; + const char *global; + const char *preload; + + preload = _appinfo_get_value(ai, AIT_PRELOAD); + global = _appinfo_get_value(ai, AIT_GLOBAL); + if (global && strncmp(global, "true", strlen("true")) == 0) { + if (preload && strncmp(preload, "true", strlen("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; +} + +char **_extractor_mountable_get_tep_paths(const struct appinfo *ai) +{ + char tep_path[PATH_MAX]; + char **mnt_path; + const char *pkgid; + const char *tep_name; + + if (ai == NULL) + return NULL; + + pkgid = _appinfo_get_value(ai, AIT_PKGID); + if (pkgid == NULL) + return NULL; + + tep_name = _appinfo_get_value(ai, 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); + snprintf(tep_path, PATH_MAX, "%s/%s/tep/mount", + __get_app_root_path(ai), pkgid); + mnt_path[0] = strdup(tep_path); + + return mnt_path; +} + +char **_extractor_mountable_get_tpk_paths(const struct appinfo *ai) +{ + char mount_point[PATH_MAX]; + char **mnt_path; + const char *pkgid; + const char *tpk; + + if (ai == NULL) + return NULL; + + pkgid = _appinfo_get_value(ai, AIT_PKGID); + if (pkgid == NULL) + return NULL; + + tpk = _appinfo_get_value(ai, 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); + snprintf(mount_point, PATH_MAX, "%s/%s/.pkg", + __get_app_root_path(ai), pkgid); + mnt_path[0] = strdup(mount_point); + + 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 struct appinfo *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 = _appinfo_get_value(ai, AIT_NAME); + g_hash_table_insert(set, strdup(appid), NULL); +} + +static bool __is_unmountable(const char *appid, const char *key) +{ + GHashTable *set; + + if (_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; +} + +void _extractor_mount(const struct appinfo *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 = malloc(sizeof(char *) * (len + 1)); + 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]); + new_array[len] = strdup(mnt_path[0]); + 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 = _appinfo_get_value(ai, AIT_PKGID); + ret = _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); +} + +void _extractor_unmount(int pid, _extractor_mountable mountable) +{ + const char *appid; + const struct appinfo *ai; + int ret; + char **mnt_path; + app_status_h app_status; + uid_t uid; + + app_status = _app_status_find(pid); + if (app_status == NULL) + return; + + uid = _app_status_get_uid(app_status); + appid = _app_status_get_appid(app_status); + if (appid == NULL) + return; + + ai = _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 = _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); +} diff --git a/src/amd_inotify.c b/src/amd_inotify.c new file mode 100644 index 0000000..edfefc9 --- /dev/null +++ b/src/amd_inotify.c @@ -0,0 +1,239 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#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 struct inotify_watch_info *__find_inotify_watch_info(int wd) +{ + struct inotify_watch_info *info; + GList *iter; + + iter = __watch_list; + while (iter) { + info = (struct inotify_watch_info *)iter->data; + if (info->wd == wd) + return info; + + iter = g_list_next(iter); + } + + return NULL; +} + +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; + + 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) { + info = __find_inotify_watch_info(e->wd); + if (info && !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; + + info = __find_inotify_watch_info(wd); + if (!info) + return; + + __watch_list = g_list_remove(__watch_list, info); + __destroy_inotify_watch_info(info); +} + +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/amd_input.c b/src/amd_input.c new file mode 100644 index 0000000..8f5c3b5 --- /dev/null +++ b/src/amd_input.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2016 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 +#include +#include + +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_input.h" +#include "amd_wayland.h" + +#define TIMEOUT_VAL 1000 + +static bool listener_added; +static bool locked; +static bool init_done; +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; +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 void __keyboard_keymap(void *data, struct wl_keyboard *keyboard, + uint32_t format, int fd, uint32_t size) +{ + char *map = NULL; + + _D("format=%d, fd=%d, size=%d", format, fd, size); + if (!g_ctx) { + _E("This client failed to make xkb context"); + close(fd); + return; + } + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + _E("Invaild format: %d", format); + close(fd); + return; + } + + map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + _E("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) + _E("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) +{ + _D("serial=%d", serial); +} + +static void __keyboard_leave(void *data, struct wl_keyboard *keyboard, + uint32_t serial, struct wl_surface *surface) +{ + _D("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) +{ + _D("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) +{ + _D("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 void __global_registry_handler(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + if (interface == NULL) + return; + + if (strcmp(interface, "tizen_input_device_manager") == 0) { + if (!input_devmgr) { + input_devmgr = wl_registry_bind(registry, id, + &tizen_input_device_manager_interface, + 1); + _D("input_devmgr = %p", input_devmgr); + } + } else if (strcmp(interface, "tizen_keyrouter") == 0) { + if (!keyrouter) { + keyrouter = wl_registry_bind(registry, id, + &tizen_keyrouter_interface, 1); + _D("keyrouter = %p", keyrouter); + } + } else if (strcmp(interface, "wl_seat") == 0) { + if (!seat) { + seat = wl_registry_bind(registry, id, + &wl_seat_interface, 1); + if (!seat) + return; + + _D("Succeed to bind wl_seat_interface!"); + keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(keyboard, &keyboard_listener, + NULL); + _D("keyboard = %p", keyboard); + } + } +} + +static void __global_registry_remover(void *data, struct wl_registry *registry, + uint32_t id) +{ + 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; + } +} + +static struct wl_registry_listener registry_listener = { + __global_registry_handler, + __global_registry_remover +}; + +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; + + nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out); + if (nsyms && syms_out && *syms_out == keysym) { + found_keycodes->nkeycodes++; + found_keycodes->keycodes = realloc(found_keycodes->keycodes, + sizeof(int) * found_keycodes->nkeycodes); + 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); + _D("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); + _D("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++) { + _D("%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++) { + _D("%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) { + _E("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) +{ + _D("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) +{ + _D("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) +{ + _D("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) +{ + _D("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) +{ + _D("%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) +{ + _E("error: %d", errorcode); +} + +static void __cb_block_expired(void *data, + struct tizen_input_device_manager *tizen_input_device_manager) +{ + _D("block expired"); +} + +static struct tizen_input_device_manager_listener input_devmgr_listener = { + __cb_device_add, + __cb_device_remove, + __cb_error, + __cb_block_expired +}; + +int _input_init(void) +{ + if (!listener_added) { + _wayland_add_registry_listener(®istry_listener, NULL); + listener_added = true; + } + + if (!display) { + display = _wayland_get_display(); + if (!display) { + _E("Failed to connect to wayland compositor"); + return -1; + } + } + + if (__xkb_init() < 0) + return -1; + + _D("Connected to wayland compositor!"); + + if (input_devmgr == NULL) { + _E("input_devmgr is null"); + return -1; + } + + if (keyrouter == NULL) { + _E("keyrouter is null"); + return -1; + } + + if (seat == NULL) { + _E("seat is null"); + return -1; + } + + if (keyboard == NULL) { + _E("keyboard is null"); + return -1; + } + + if (tizen_input_device_manager_add_listener(input_devmgr, + &input_devmgr_listener, NULL) < 0) { + _E("Failed to add listener"); + } + wl_display_flush(display); + wl_display_roundtrip(display); + + if (g_keymap == NULL) { + _E("g_keymap is null"); + return -1; + } + + init_done = true; + + return 0; +} + +int _input_fini(void) +{ + __xkb_fini(); + + return 0; +} + +int _input_lock(void) +{ + if (locked) + _input_unlock(); + + if (!init_done && _input_init() < 0) + return -1; + + _D("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; +} + +int _input_unlock(void) +{ + if (!locked) + return 0; + + if (!init_done && _input_init() < 0) + return -1; + + _D("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/src/amd_launch.c b/src/amd_launch.c new file mode 100644 index 0000000..d59453c --- /dev/null +++ b/src/amd_launch.c @@ -0,0 +1,1983 @@ +/* + * Copyright (c) 2000 - 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amd_launch.h" +#include "amd_appinfo.h" +#include "amd_app_status.h" +#include "amd_app_group.h" +#include "amd_util.h" +#include "app_signal.h" +#include "amd_socket.h" +#include "amd_share.h" +#include "amd_app_com.h" +#include "amd_splash_screen.h" +#include "amd_input.h" +#include "amd_suspend.h" +#include "amd_signal.h" +#include "amd_extractor.h" +#include "amd_app_property.h" +#include "amd_cooldown.h" +#include "amd_widget.h" +#include "amd_screen_connector.h" +#include "amd_rua.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" + +struct launch_s { + const char *appid; + const struct appinfo *ai; + const char *instance_id; + int pid; + int leader_pid; + bool can_attach; + bool new_process; + bool is_subapp; + app_group_launch_mode launch_mode; + int prelaunch_attr; + int bg_category; + int bg_allowed; + shared_info_h share_info; + 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); +extern void _cleanup_dead_info(app_status_h app_status); + +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; + +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 __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; + int cnt; + int *pids = NULL; + int i; + uid_t uid = _request_get_target_uid(req); + + if (_app_group_is_leader_pid(pid)) { + _app_group_get_group_pids(pid, &cnt, &pids); + for (i = cnt - 1; i >= 0; i--) { + if (i != 0) + _term_sub_app(pids[i], uid); + _app_group_remove(pids[i]); + } + free(pids); + } + + 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; + int cnt; + int *pids = NULL; + int i; + int status = -1; + app_status_h app_status; + uid_t uid = _request_get_target_uid(req); + + if (_app_group_is_leader_pid(pid)) { + _app_group_get_group_pids(pid, &cnt, &pids); + if (cnt > 0) { + app_status = _app_status_find(pids[cnt - 1]); + status = _app_status_get_status(app_status); + if (status == STATUS_BG) { + for (i = cnt - 1 ; i >= 0; i--) { + if (i != 0) + _term_sub_app(pids[i], uid); + _app_group_remove(pids[i]); + } + } + } + free(pids); + } + + 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; + int cnt; + int *pids = NULL; + int i; + uid_t uid = _request_get_target_uid(req); + + if (_app_group_is_leader_pid(pid)) { + _app_group_get_group_pids(pid, &cnt, &pids); + for (i = cnt - 1; i >= 0; i--) { + if (i != 0) + _term_sub_app(pids[i], uid); + _app_group_remove(pids[i]); + } + free(pids); + } + + 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; + bundle *kb; +}; + +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); + if (r_info->kb) + bundle_free(r_info->kb); + 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); + if (_app_status_get_app_type(app_status) == AT_WIDGET_APP) + _widget_verify_instance(r_info->kb, r_info->pid, uid); + + 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); + if (r_info->kb) + bundle_free(r_info->kb); + 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; + bundle *kb = _request_get_bundle(req); + + 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; + } + + if (kb) { + r_info->kb = bundle_dup(kb); + if (r_info->kb == NULL) { + _E("Out of memory"); + free(r_info); + g_free(gpollfd); + g_source_unref(src); + return; + } + } else { + r_info->kb = NULL; + } + + 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 int __get_pid_for_app_group(const char *appid, uid_t uid, bundle *kb, + struct launch_s *handle) +{ + int status; + int found_pid = -1; + int found_lpid = -1; + int ret; + + if (_app_group_is_group_app(kb, uid)) { + handle->pid = -1; + handle->is_subapp = true; + handle->app_status = NULL; + } else { + if (handle->new_instance) + handle->is_subapp = true; + else + handle->is_subapp = false; + } + + status = _app_status_get_status(handle->app_status); + if (handle->pid <= 0 || status == STATUS_DYING) { + ret = _app_group_find_singleton(appid, &found_pid, &found_lpid); + if (ret == 0) { + handle->pid = found_pid; + handle->new_process = false; + } else { + handle->new_process = true; + } + + ret = _app_group_can_start_app(appid, kb, &handle->can_attach, + &handle->leader_pid, &handle->launch_mode, uid); + if (ret != 0) { + _E("can't make group info"); + return -EILLEGALACCESS; + } + + if (handle->can_attach && handle->leader_pid == found_lpid) { + _E("can't launch singleton app in the same group"); + return -EILLEGALACCESS; + } + + if (found_pid != -1) { + _W("_app_group_clear_top, pid: %d", found_pid); + _app_group_clear_top(found_pid, uid); + } + } + + if (handle->pid == -1 && handle->can_attach) + handle->pid = _app_group_find_pid_from_recycle_bin(appid); + + if (handle->pid > 0) + handle->app_status = _app_status_find(handle->pid); + + return 0; +} + +static void __prepare_to_suspend_services(int pid, uid_t uid) +{ + int dummy; + + 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; + + 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_services); + + 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; +} + +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; +} + +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; +} + +#ifdef TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP +static void __terminate_unmanageable_app(app_status_h app_status) +{ + const char *appid = NULL; + int cnt = 0; + int *pids = NULL; + int i; + const char *taskmanage = NULL; + const struct appinfo *ai = NULL; + int bg_category = 0x00; + app_status_h status_h; + int st; + uid_t uid; + + if (!_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 = _app_status_find(pids[i]); + if (!status_h) + continue; + + if (_app_status_is_home_app(status_h)) + continue; + + appid = _app_status_get_appid(status_h); + ai = _appinfo_find(_app_status_get_uid(status_h), appid); + taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE); + _appinfo_get_int_value(ai, AIT_BG_CATEGORY, &bg_category); + uid = _app_status_get_uid(status_h); + + if (taskmanage && strcmp("false", taskmanage) == 0 + && bg_category == 0) { + st = _app_status_get_status(status_h); + if (st == STATUS_BG) { + _W("terminate %d %s %d", pids[i], appid, st); + aul_send_app_terminate_request_signal(pids[i], + NULL, NULL, NULL); + _term_sub_app(pids[i], uid); + } + } + } + + free(pids); +} +#endif /* TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP */ + +static const char *__get_name(const char *appid) +{ + char *name_token; + + if (!appid) + return NULL; + + name_token = strrchr(appid, '.'); + if (name_token == NULL) + return appid; + + name_token++; + + return name_token; +} + +static int __app_status_handler(int pid, int status, void *data) +{ + const char *appid; + const char *name; + int bg_category; + int old_status; + const struct appinfo *ai; + app_status_h app_status; + uid_t uid; + unsigned int surf; + + _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); + +#ifdef TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP + __terminate_unmanageable_app(app_status); +#endif /* TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP */ + + surf = (unsigned int)_app_group_get_window(pid); + _screen_connector_update_app_screen(pid, surf, uid); + _rua_update_screen_info(pid, surf); + break; + case PROC_STATUS_BG: + _app_status_update_status(app_status, STATUS_BG, false, true); + appid = _app_status_get_appid(app_status); + if (appid) { + ai = _appinfo_find(uid, appid); + bg_category = (bool)_appinfo_get_value(ai, + AIT_BG_CATEGORY); + if (!bg_category) + _suspend_add_timer(pid, ai); + } + break; + case PROC_STATUS_FOCUS: + __focused_pid = pid; + surf = (unsigned int)_app_group_get_window(pid); + _screen_connector_update_app_screen(pid, surf, uid); + _rua_update_screen_info(pid, surf); + break; + + case PROC_STATUS_HIDE: + _app_status_update_status(app_status, STATUS_BG, false, false); + break; + + case PROC_STATUS_LAUNCH: + _signal_send_cpu_boost(APP_BOOSTING_STOP); + appid = _app_status_get_appid(app_status); + if (appid) { + name = __get_name(appid); + if (name) + LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]", name); + } + 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; +} + +int _launch_init(void) +{ + int ret; + + _D("_launch_init"); + + ret = __listen_app_status_signal(NULL); + if (ret < 0) + _signal_add_initializer(__listen_app_status_signal, NULL); + + 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_BACKGROUND_MANAGEMENT_ATTRIBUTE; + const char *api_version; + const char *comp; + const char *pkg_type; + bool system = false; + app_property_h prop; + + 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) { + if (_app_property_metadata_query_activation(prop, appid, METADATA_LARGEMEMORY)) + attribute_val |= RESOURCED_ATTRIBUTE_LARGEMEMORY; + if (_app_property_metadata_query_activation(prop, appid, METADATA_OOMTERMINATION)) + 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 bool __is_allowed_background(const char *component_type, int bg_category) +{ + bool bg_allowed = false; + + /* + * 2.4 bg-categorized (uiapp || svcapp) || watch || widget -> bg allowed + * 2.3 uiapp -> not allowed, 2.3 svcapp -> bg allowed + */ + if (!strcmp(component_type, APP_TYPE_UI) || + !strcmp(component_type, APP_TYPE_SERVICE)) { + if (bg_category) + bg_allowed = true; + } else { + bg_allowed = true; + } + + return bg_allowed; +} + +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; + 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); +#ifdef TIZEN_FEATURE_BLOCK_INPUT + int status; +#endif /* TIZEN_FEATURE_BLOCK_INPUT */ + 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 = _cooldown_check_mode(handle->ai); + if (ret < 0) { + _E("Unable to launch %s in cooldown mode", handle->appid); + return ret; + } + + 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) { + ret = __get_pid_for_app_group(appid, target_uid, kb, handle); + if (ret < 0) + return ret; + +#ifdef TIZEN_FEATURE_BLOCK_INPUT + status = _app_status_get_status(handle->app_status); + if (status != STATUS_VISIBLE && !handle->bg_launch) + _input_lock(); +#endif /* TIZEN_FEATURE_BLOCK_INPUT */ + } 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; + } else if (caller_appid && strcmp(comp_type, APP_TYPE_WIDGET) == 0) { + ret = _widget_verify_cmd(req); + if (ret < 0) + return ret; + } + + if (cmd == APP_START_RES) { + bundle_del(kb, AUL_K_WAIT_RESULT); + bundle_add(kb, AUL_K_WAIT_RESULT, "1"); + } + + if (caller_appid) { + handle->share_info = _temporary_permission_create(caller_pid, + appid, kb, target_uid); + if (handle->share_info == NULL) + _W("No sharable path: %d %s", caller_pid, appid); + } + + _extractor_mount(handle->ai, kb, _extractor_mountable_get_tep_paths); + _extractor_mount(handle->ai, kb, _extractor_mountable_get_tpk_paths); + + handle->prelaunch_attr = __get_prelaunch_attribute( + handle->ai, appid, target_uid); + handle->bg_category = __get_background_category(handle->ai); + handle->bg_allowed = __is_allowed_background(comp_type, + handle->bg_category); + 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; + const char *pad_type = LAUNCHPAD_PROCESS_POOL_SOCK; + splash_image_h splash_image = NULL; + int ret; + char err_buf[1024]; + bool socket_exists; + + 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) { + _temporary_permission_destroy(handle->share_info); + 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; + } + + if (handle->instance_id == NULL && handle->bg_launch == false) { + splash_image = _splash_screen_create_image(handle->ai, kb, cmd, + handle->is_subapp); + _splash_screen_send_image(splash_image); + } + + _signal_send_proc_prelaunch(handle->appid, pkgid, + handle->prelaunch_attr, handle->bg_category); + _signal_send_cpu_boost(APP_BOOSTING_PERIOD); + + if (__get_tizen_profile() == TIZEN_PROFILE_WEARABLE) + bundle_add(kb, AUL_K_PROFILE, "wearable"); + ret = _send_cmd_to_launchpad(pad_type, target_uid, PAD_CMD_LAUNCH, kb); + if (ret < 0) { + _signal_send_cpu_boost(APP_BOOSTING_STOP); + _temporary_permission_destroy(handle->share_info); + _splash_screen_destroy_image(splash_image); + return ret; + } + + handle->pid = ret; + *pending = true; + *bg_launch = handle->bg_launch; + + if (splash_image) { + _splash_screen_send_pid(splash_image, handle->pid); + } else if (comp_type && !strcmp(comp_type, APP_TYPE_UI)) { + _splash_screen_set_effect_type(handle->pid, handle->appid, + handle->is_subapp); + } + + _suspend_add_proc(handle->pid); + aul_send_app_launch_request_signal(handle->pid, handle->appid, + pkgid, comp_type); + + _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 (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; + int ret; + char log_status[AUL_PR_NAME]; + + comp_type = _appinfo_get_value(handle->ai, AIT_COMPTYPE); + if (comp_type && !strcmp(comp_type, APP_TYPE_UI)) { + if (handle->new_process) { + _D("Add app group info %d", handle->pid); + __pid_of_last_launched_ui_app = handle->pid; + _app_group_start_app(handle->pid, kb, + handle->leader_pid, + handle->can_attach, + handle->launch_mode); + } else { + _app_group_restart_app(handle->pid, kb); + } + } + + _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); + + if (handle->share_info) { + ret = _temporary_permission_apply(handle->pid, target_uid, + handle->share_info); + if (ret < 0) + _D("Couldn't apply temporary permission: %d", ret); + + _temporary_permission_destroy(handle->share_info); + } + + 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; +} diff --git a/src/amd_login_monitor.c b/src/amd_login_monitor.c new file mode 100644 index 0000000..8183739 --- /dev/null +++ b/src/amd_login_monitor.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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_wayland.h" +#include "amd_socket.h" +#include "amd_request.h" +#include "amd_screen_connector.h" +#include "amd_launch.h" +#include "amd_signal.h" +#include "amd_rua.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 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_OPENING | UID_STATE_ONLINE | + UID_STATE_ACTIVE, + .login = _screen_connector_usr_init + }, + { + .state = UID_STATE_ONLINE | UID_STATE_ACTIVE, + .login = _request_usr_init + }, + { + .state = UID_STATE_ACTIVE, + .login = _launch_start_onboot_apps + }, + { + .state = UID_STATE_ONLINE | UID_STATE_ACTIVE, + .login = _rua_usr_init + } +}; +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 + }, + { + .state = UID_STATE_CLOSING | UID_STATE_OFFLINE, + .logout = _screen_connector_usr_fini + }, + { + .state = UID_STATE_CLOSING | UID_STATE_OFFLINE, + .logout = _rua_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); + } + } +} + +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); + } + } +} + +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 __startup_finished_cb(uid_t uid, void *user_data) +{ + 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 __subscribe_startup_finished(void *data) +{ + return _signal_subscribe_startup_finished(__startup_finished_cb, data); +} + +int _login_monitor_init(void) +{ + uid_t uid; + struct user_s *user; + + _D("login monitor init"); + if (__init_login_monitor()) { + _E("Failed to initialize login monitor"); + __fini_login_monitor(); + return -1; + } + + __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 -1; + } + user->uid = uid; + user->timer = 0; + user->state = UID_STATE_OPENING; + user_list = g_list_append(user_list, user); + __user_login(user); + } + + if (__subscribe_startup_finished(NULL) < 0) + _signal_add_initializer(__subscribe_startup_finished, NULL); + + return 0; +} + +void _login_monitor_fini(void) +{ + _D("login monitor fini"); + + _signal_unsubscribe_startup_finished(); + + if (user_list) + g_list_free_full(user_list, free); + + __fini_login_monitor(); +} diff --git a/src/amd_main.c b/src/amd_main.c new file mode 100644 index 0000000..07d98ac --- /dev/null +++ b/src/amd_main.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2000 - 2016 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_appinfo.h" +#include "amd_app_status.h" +#include "amd_launch.h" +#include "amd_request.h" +#include "amd_app_group.h" +#include "amd_cynara.h" +#include "amd_app_com.h" +#include "amd_share.h" +#include "amd_socket.h" +#include "amd_splash_screen.h" +#include "amd_input.h" +#include "amd_signal.h" +#include "amd_wayland.h" +#include "amd_extractor.h" +#include "amd_suspend.h" +#include "amd_widget.h" +#include "amd_app_property.h" +#include "amd_screen_connector.h" +#include "amd_login_monitor.h" +#include "amd_rua.h" +#include "amd_inotify.h" + +struct restart_info { + char *appid; + int count; + guint timer; +}; + +static GHashTable *restart_tbl; + +static gboolean __restart_timeout_handler(void *data) +{ + struct restart_info *ri = (struct restart_info *)data; + + _D("ri (%x)", 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 = malloc(sizeof(struct restart_info)); + if (!ri) { + _E("create restart info: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + return false; + } + memset(ri, 0, sizeof(struct restart_info)); + ri->appid = strdup(appid); + ri->count = 1; + g_hash_table_insert(restart_tbl, ri->appid, ri); + + _D("ri (%x)", 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; + splash_image_h splash_image; + uid_t uid; + char buf[MAX_LOCAL_BUFSZ]; + int app_type; + + if (pid <= 0) + return 0; + + _D("APP_DEAD_SIGNAL : %d", pid); + + splash_image = _splash_screen_get_image(pid); + if (splash_image) + _splash_screen_destroy_image(splash_image); + + app_status = _app_status_find(pid); + if (app_status == NULL) + return 0; + + tmp_appid = _app_status_get_appid(app_status); + if (tmp_appid == NULL) + return 0; + + uid = _app_status_get_uid(app_status); + app_type = _app_status_get_app_type(app_status); + + if (app_type == AT_WIDGET_APP) { + _widget_dead_handler( + pid, + uid, + _app_status_get_pkgid(app_status), + _app_status_get_org_caller_pid(app_status), + _app_status_get_is_exit_notified(app_status), + __check_restart(tmp_appid) + ); + } else if (app_type == AT_WATCH_APP) { + _app_status_fault_recovery( + pid, + uid, + _app_status_get_pkgid(app_status), + tmp_appid, + app_type, + _app_status_get_is_exit_notified(app_status)); + + } + + restart = __can_restart_app(tmp_appid, uid); + if (restart) + appid = strdup(tmp_appid); + + _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 __init(void) +{ + int r; + + 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; + } + + _request_init(); + _app_status_init(); + _app_group_init(); + _app_com_broker_init(); + _launch_init(); + _splash_screen_init(); +#ifdef TIZEN_FEATURE_BLOCK_INPUT + _input_init(); +#endif /* TIZEN_FEATURE_BLOCK_INPUT */ + _wayland_init(); + _suspend_init(); + _signal_init(); + _widget_init(); + _app_property_init(); + _screen_connector_init(); + _login_monitor_init(); + _util_init(); + _rua_init(); + _inotify_init(); + + 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) +{ + _inotify_fini(); + _rua_fini(); + _util_fini(); + _login_monitor_fini(); + _screen_connector_fini(); + _app_property_fini(); + _widget_fini(); + _suspend_fini(); + _wayland_finish(); +#ifdef TIZEN_FEATURE_BLOCK_INPUT + _input_fini(); +#endif /* TIZEN_FEATURE_BLOCK_INPUT */ + _app_com_broker_fini(); + _app_group_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(); +} + +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/amd_request.c b/src/amd_request.c new file mode 100644 index 0000000..473de1b --- /dev/null +++ b/src/amd_request.c @@ -0,0 +1,3927 @@ +/* + * Copyright (c) 2000 - 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_request.h" +#include "amd_launch.h" +#include "amd_appinfo.h" +#include "amd_app_status.h" +#include "amd_app_group.h" +#include "amd_cynara.h" +#include "amd_socket.h" +#include "amd_app_com.h" +#include "amd_share.h" +#include "amd_input.h" +#include "amd_widget.h" +#include "aul_svc_priv_key.h" +#include "amd_signal.h" +#include "amd_app_property.h" +#include "amd_screen_connector.h" +#include "amd_login_monitor.h" +#include "amd_rua.h" + +#define INHOUSE_UID tzplatform_getuid(TZ_USER_NAME) + +#define MAX_NR_OF_DESCRIPTORS 2 +#define PENDING_REQUEST_TIMEOUT 5000 /* msec */ +#define SYSTEM_REQUEST_TIMEOUT 90000 /* msec */ +#define PENDING_MESSAGE_MAX_CNT 100 +#define MULTI_INSTANCE_SHORTCUT "multi-instance-shortcut" +#define QUERY_KEY_ID "id=" +#define QUERY_KEY_ICON "icon=" +#define QUERY_KEY_NAME "name=" + +static int amd_fd; +static GIOChannel *amd_io; +static guint amd_wid; +static GHashTable *__dc_socket_pair_hash; +static GHashTable *pending_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]; +}; + +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 reply_info { + guint timer; + pid_t pid; + int result; + int cmd; + int clifd; + rua_stat_pkt_t *rua; +}; + +struct instance_info { + char *id; + char *name; + char *icon; + char *uri; +}; + +typedef int (*app_cmd_dispatch_func)(request_h req); +static gboolean __timeout_pending_item(gpointer user_data); +static gboolean __dispatch_request(gpointer data); +static gboolean __timeout_request(gpointer data); +static gboolean __timeout_reply(gpointer data); +static struct reply_info *__create_reply_info(guint interval, pid_t pid, + int result, int cmd, int clifd, rua_stat_pkt_t *rua); + +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 __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 __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 (req->cmd) { + 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 (req->cmd) { + 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, req->cmd, + (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", req->cmd); + ret = -1; + } + + return ret; +} + +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 void __free_rua_stat_pkt(rua_stat_pkt_t *pkt) +{ + 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 gboolean __add_history_handler(gpointer user_data) +{ + struct rua_rec rec = { 0, }; + int ret; + struct appinfo *ai; + rua_stat_pkt_t *pkt = (rua_stat_pkt_t *)user_data; + + if (!pkt) + return FALSE; + + if (!pkt->is_group_app) { + ai = _appinfo_find(pkt->uid, pkt->appid); + + rec.pkg_name = pkt->appid; + rec.app_path = (char *)_appinfo_get_value(ai, 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) + _D("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 rua_stat_pkt_t *__create_rua_stat_pkt(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; + + rua_stat_item = calloc(1, sizeof(rua_stat_pkt_t)); + if (rua_stat_item == NULL) { + _E("out of memory"); + return NULL; + } + + rua_stat_item->pid = pid; + + if (req->len > 0) { + rua_stat_item->data = calloc(req->len + 1, sizeof(char)); + if (rua_stat_item->data == NULL) { + _E("out of memory"); + __free_rua_stat_pkt(rua_stat_item); + return NULL; + } + memcpy(rua_stat_item->data, req->data, req->len); + } + rua_stat_item->len = req->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) { + _E("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) { + _E("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) { + _E("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) { + _E("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) { + _E("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) { + _E("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) { + _E("Out of memory"); + __free_rua_stat_pkt(rua_stat_item); + return NULL; + } + } + + rua_stat_item->uid = _request_get_target_uid(req); + rua_stat_item->is_group_app = _app_group_is_group_app(kb, + rua_stat_item->uid); + + return rua_stat_item; +} + +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; + struct timeval read_timeout; + struct timeval write_timeout; + + if (socketpair(AF_UNIX, SOCK_STREAM, 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; + } + + read_timeout.tv_sec = 5; + read_timeout.tv_usec = 0; + write_timeout.tv_sec = 25; /*dbus default timeout */ + write_timeout.tv_usec = 0; + + ret = setsockopt(handles[0], SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof(read_timeout)); + if (ret < 0) { + _E("Cannot Set SO_RCVTIMEO for socket %d", handles[0]); + _request_send_result(req, -1); + goto out; + } + + ret = setsockopt(handles[0], SOL_SOCKET, SO_SNDTIMEO, &write_timeout, sizeof(write_timeout)); + if (ret < 0) { + _E("Cannot Set SO_SNDTIMEO for socket %d", handles[0]); + _request_send_result(req, -1); + goto out; + } + + ret = setsockopt(handles[1], SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof(read_timeout)); + if (ret < 0) { + _E("Cannot Set SO_RCVTIMEO for socket %d", handles[1]); + _request_send_result(req, -1); + goto out; + } + + ret = setsockopt(handles[1], SOL_SOCKET, SO_SNDTIMEO, &write_timeout, sizeof(write_timeout)); + if (ret < 0) { + _E("Cannot Set SO_SNDTIMEO for socket %d", handles[1]); + _request_send_result(req, -1); + goto out; + } + + _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(req->clifd, vec, 1, handles, 2); + if (msglen < 0) { + _E("Error[%d]: while sending message\n", -msglen); + _request_send_result(req, -1); + ret = -1; + } +out: + close(handles[0]); + close(handles[1]); + + return ret; +} + +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 = req->kb; + struct timeval tv; + int ret; + + 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_CONTOL_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 = g_hash_table_lookup(__dc_socket_pair_hash, socket_pair_key); + if (handles == NULL) { + handles = (int *)calloc(2, sizeof(int)); + if (handles == NULL) { + _E("calloc fail"); + goto err_out; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) { + _E("error create socket pair"); + _request_send_result(req, -1); + free(handles); + handles = NULL; + goto err_out; + } + + if (handles[0] == -1 || handles[1] == -1) { + _E("error socket open"); + _request_send_result(req, -1); + free(handles); + handles = NULL; + goto err_out; + } + + tv.tv_sec = 5; + tv.tv_usec = 0; + ret = setsockopt(handles[0], SOL_SOCKET, SO_RCVTIMEO, &tv, + sizeof(tv)); + if (ret < 0) { + _E("Cannot Set SO_RCVTIMEO for socket %d", handles[0]); + _request_send_result(req, -1); + close(handles[0]); + close(handles[1]); + free(handles); + handles = NULL; + goto err_out; + } + + ret = setsockopt(handles[1], SOL_SOCKET, SO_RCVTIMEO, &tv, + sizeof(tv)); + if (ret < 0) { + _E("Cannot Set SO_RCVTIMEO for socket %d", handles[1]); + _request_send_result(req, -1); + close(handles[0]); + close(handles[1]); + 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; + + if (datacontrol_type != NULL) { + _D("datacontrol_type : %s", datacontrol_type); + if (strcmp(datacontrol_type, "consumer") == 0) { + msglen = __send_message(req->clifd, vec, 1, + &handles[0], 1); + if (msglen < 0) { + _E("Error[%d]: while sending message", -msglen); + _request_send_result(req, -1); + goto err_out; + } + close(handles[0]); + handles[0] = -1; + if (handles[1] == -1) { + _E("remove from hash : %s", socket_pair_key); + g_hash_table_remove(__dc_socket_pair_hash, + socket_pair_key); + } + + } else { + msglen = __send_message(req->clifd, vec, 1, + &handles[1], 1); + if (msglen < 0) { + _E("Error[%d]: while sending message", -msglen); + _request_send_result(req, -1); + goto err_out; + } + close(handles[1]); + handles[1] = -1; + if (handles[0] == -1) { + _E("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: + if (socket_pair_key) { + g_hash_table_remove(__dc_socket_pair_hash, socket_pair_key); + free(socket_pair_key); + } + + return -1; +} + +static int __dispatch_update_rua_stat(request_h req) +{ + int result; + char *caller = NULL; + char *tag = NULL; + uid_t uid = _request_get_target_uid(req); + + bundle_get_str(req->kb, AUL_SVC_K_RUA_STAT_CALLER, &caller); + bundle_get_str(req->kb, AUL_SVC_K_RUA_STAT_TAG, &tag); + result = rua_stat_usr_db_update(caller, tag, uid); + _D("rua_stat_usr_db_update - uid(%d), result(%d)", uid, result); + _request_send_result(req, result); + + return 0; +} + +static int __dispatch_add_history(request_h req) +{ + int result; + struct rua_rec rec = {0,}; + char *time_str; + uid_t uid = _request_get_target_uid(req); + bundle *b = _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); + _D("rua_usr_db_add_history - uid(%d), result(%d)", uid, result); + _request_send_result(req, result); + + return 0; +} + +static int __dispatch_remove_history(request_h req) +{ + int result; + bundle *b = _request_get_bundle(req); + uid_t uid = _request_get_target_uid(req); + + result = rua_usr_db_delete_history(b, uid); + _D("rua_usr_db_delete_history - uid(%d), result(%d)", uid, result); + _request_send_result(req, result); + + _rua_delete_info(b, uid); + + return 0; +} + +static int __dispatch_app_group_get_window(request_h req) +{ + char *buf; + int pid; + int wid; + + bundle_get_str(req->kb, AUL_K_PID, &buf); + pid = atoi(buf); + wid = _app_group_get_window(pid); + _request_send_result(req, wid); + + return 0; +} + +static int __dispatch_app_group_set_window(request_h req) +{ + char *buf; + int pid = _request_get_pid(req); + uid_t uid = _request_get_target_uid(req); + int wid; + int ret; + + bundle_get_str(req->kb, AUL_K_WID, &buf); + wid = atoi(buf); + ret = _app_group_set_window(pid, wid); + _request_send_result(req, ret); + _D("pid(%d), wid(%d)", pid, wid); + _screen_connector_add_app_screen(pid, wid, NULL, uid); + + return ret; +} + +static int __dispatch_app_group_get_fg_flag(request_h req) +{ + char *buf; + int pid; + int fg; + + bundle_get_str(req->kb, AUL_K_PID, &buf); + pid = atoi(buf); + fg = _app_group_get_fg_flag(pid); + _request_send_result(req, fg); + + return 0; +} + +static int __dispatch_app_group_clear_top(request_h req) +{ + int pid = _request_get_pid(req); + uid_t uid = _request_get_target_uid(req); + + _app_group_clear_top(pid, uid); + _request_send_result(req, 0); + + return 0; +} + +static int __dispatch_app_group_get_leader_pid(request_h req) +{ + char *buf; + int pid; + int lpid; + + bundle_get_str(req->kb, AUL_K_PID, &buf); + pid = atoi(buf); + lpid = _app_group_get_leader_pid(pid); + _request_send_result(req, lpid); + + return 0; +} + +static int __dispatch_app_group_get_leader_pids(request_h req) +{ + int cnt; + int *pids; + unsigned char empty[1] = {0,}; + + _app_group_get_leader_pids(&cnt, &pids); + + if (pids == NULL || cnt == 0) { + _request_send_raw(req, APP_GROUP_GET_LEADER_PIDS, empty, 0); + } else { + _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(request_h req) +{ + int cnt; + int *pids; + unsigned char empty[1] = {0,}; + + _app_group_get_idle_pids(&cnt, &pids); + if (pids == NULL || cnt == 0) { + _request_send_raw(req, APP_GROUP_GET_IDLE_PIDS, empty, 0); + } else { + _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(request_h req) +{ + char *buf; + int leader_pid; + int cnt; + int *pids; + unsigned char empty[1] = { 0 }; + + bundle_get_str(req->kb, AUL_K_LEADER_PID, &buf); + leader_pid = atoi(buf); + + _app_group_get_group_pids(leader_pid, &cnt, &pids); + if (pids == NULL || cnt == 0) { + _request_send_raw(req, APP_GROUP_GET_GROUP_PIDS, empty, 0); + } else { + _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(request_h req) +{ + int ret = 0; + + _app_group_lower(req->pid, &ret); + _request_send_result(req, ret); + + return ret; +} + +static int __dispatch_app_group_activate_below(request_h req) +{ + char *buf = NULL; + int ret; + + bundle_get_str(req->kb, AUL_K_APPID, &buf); + ret = _app_group_activate_below(req->pid, buf); + _request_send_result(req, ret); + + return 0; +} + +static int __dispatch_app_group_activate_above(request_h req) +{ + char *buf = NULL; + int ret; + + bundle_get_str(req->kb, AUL_K_APPID, &buf); + ret = _app_group_activate_above(req->pid, buf); + _request_send_result(req, ret); + + return 0; +} + +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; +} + +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 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 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) { + _E("Out of memory"); + return -1; + } + + info->uri = strdup(uri); + if (info->uri == NULL) { + _E("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) { + _W("Failed to get instance info"); + __free_instance_info(info); + return -1; + } + + return 0; +} + +static int __dispatch_app_start(request_h req) +{ + const char *appid; + const char *instance_id; + int ret; + bundle *kb; + bool pending = false; + struct pending_item *item; + GTimeVal end; + guint interval; + bool bg_launch = false; + bool new_instance = false; + struct instance_info info = {0,}; + struct reply_info *reply; + int clifd; + rua_stat_pkt_t *rua = NULL; + + kb = req->kb; + if (kb == NULL) + return -1; + + __set_real_appid(_request_get_target_uid(req), kb); + __set_effective_appid(_request_get_target_uid(req), kb); + 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; + _D("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); + _D("Multiple instance launch - id(%s)", info.id); + } + } + + appid = bundle_get_val(kb, AUL_K_APPID); + ret = _launch_start_app(appid, req, &pending, &bg_launch, new_instance); +#ifdef TIZEN_FEATURE_BLOCK_INPUT + if (ret <= 0) + _input_unlock(); +#endif /* TIZEN_FEATURE_BLOCK_INPUT */ + + /* add pending list to wait app launched successfully */ + if (pending) { + item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(ret)); + if (item == NULL) { + item = calloc(1, sizeof(struct pending_item)); + if (item == NULL) { + _E("Out of memory"); + _request_send_result(req, ret); + __free_instance_info(&info); + return -1; + } + item->pid = ret; + g_hash_table_insert(pending_table, GINT_TO_POINTER(ret), + item); + } else { + if (item->timer) { + g_source_remove(item->timer); + item->timer = 0; + } + } + + 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); + } + + clifd = _request_remove_fd(req); + g_get_current_time(&end); + interval = __get_pending_interval(&req->start, &end); + reply = __create_reply_info(interval, ret, ret, + req->cmd, clifd, rua); + if (reply == NULL) { + _send_result_to_client(clifd, ret); + __free_instance_info(&info); + return -1; + } + + item->reply_list = g_list_append(item->reply_list, reply); + __free_instance_info(&info); + return 0; + } + + if (ret > 0 && !bg_launch) { + rua = __create_rua_stat_pkt(req, kb, appid, &info, ret); + if (rua == NULL) { + __free_instance_info(&info); + return -1; + } + g_timeout_add(1500, __add_history_handler, rua); + } + __free_instance_info(&info); + + 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 __dispatch_app_result(request_h req) +{ + bundle *kb; + int pid; + int pgid; + char tmp_pid[MAX_PID_STR_BUFSZ]; + int res; + shared_info_h si = NULL; + const char *appid; + int ret; + uid_t target_uid = _request_get_target_uid(req); + app_status_h app_status; + + kb = req->kb; + if (kb == NULL) + return -1; + + pid = __get_caller_pid(kb); + if (pid < 0) + return AUL_R_ERROR; + + pgid = getpgid(req->pid); + 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); + if (appid) { + si = _temporary_permission_create(pgid, appid, kb, target_uid); + if (si == NULL) + _D("No sharable path : %d %s", pgid, appid); + } + + res = aul_sock_send_bundle(pid, target_uid, req->cmd, kb, + AUL_SOCK_NOREPLY); + if (res < 0) + res = AUL_R_ERROR; + + if (si) { + if (res >= 0) { + ret = _temporary_permission_apply(pid, target_uid, si); + if (ret != 0) { + _D("Couldn't apply temporary permission: %d", + ret); + } + } + _temporary_permission_destroy(si); + } + + return 0; +} + +static int __dispatch_app_pause(request_h req) +{ + const char *appid; + bundle *kb; + int ret; + app_status_h app_status; + + kb = req->kb; + 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 __dispatch_app_process_by_pid(request_h req) +{ + const char *appid; + bundle *kb; + + kb = req->kb; + 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 = req->kb; + 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 = req->kb; + 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_running_info(request_h req) +{ + int ret; + + ret = _app_status_send_running_appinfo(_request_remove_fd(req), + req->cmd, _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), + req->cmd, _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_legacy_command(request_h req) +{ + _request_send_result(req, 0); + 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(req->pid); + if (app_status == NULL) + return -1; + + status = (int *)req->data; + 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_add_loader(request_h req) +{ + bundle *kb; + int ret; + char tmpbuf[MAX_PID_STR_BUFSZ]; + + kb = req->kb; + if (kb == NULL) + return -1; + + snprintf(tmpbuf, sizeof(tmpbuf), "%d", getpgid(req->pid)); + 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 = req->kb; + 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_amd_reload_appinfo(request_h req) +{ + _D("AMD_RELOAD_APPINFO"); + _appinfo_reload(); + _request_send_result(req, 0); + + return 0; +} + +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 = req->kb; + 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(req->pid), 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 = req->kb; + 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(req->pid), 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 = req->kb; + 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 = req->kb; + 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(req->pid)); + _request_send_result(req, ret); + + return 0; +} + +static int __dispatch_app_register_pid(request_h req) +{ + bundle *kb; + const 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 = req->kb; + 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); + if (component_type && strcmp(component_type, APP_TYPE_UI) == 0) { + _app_group_start_app(pid, kb, pid, FALSE, + APP_GROUP_LAUNCH_MODE_SINGLE); + } + + _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_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 = req->kb; + 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 *)req->data); + + 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_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 = req->kb; + 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; +} + +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_app_term_sync(request_h req) +{ + int ret; + int pid; + const char *appid; + bundle *kb; + struct pending_item *item; + bool pending = false; + GTimeVal end; + guint interval; + struct reply_info *reply; + int clifd; + + kb = req->kb; + 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); + clifd = _request_remove_fd(req); + g_get_current_time(&end); + interval = __get_pending_interval(&req->start, &end); + reply = __create_reply_info(interval, pid, -EAGAIN, + req->cmd, clifd, NULL); + if (reply == NULL) { + _send_result_to_client(clifd, ret); + return -1; + } + + 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); + item->timer = g_timeout_add(interval, __timeout_pending_item, + item); + } + + 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(req->kb, 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_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 __validate_widget_owner(request_h req) +{ + app_status_h status; + const char *appid; + char *widget_id = NULL; + const char *appid_part = NULL; + bundle *kb = req->kb; + + status = _app_status_find(req->pid); + if (!status) + return -1; + + appid = _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(request_h req) +{ + bundle *kb = req->kb; + char *widget_id = NULL; + char *instance_id = NULL; + int ret; + + if (__validate_widget_owner(req) < 0) { + _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) { + _request_send_result(req, -EINVAL); + return -1; + } + + if (req->cmd == WIDGET_ADD) + ret = _widget_add(widget_id, instance_id, req->pid, req->uid); + else + ret = _widget_del(widget_id, instance_id); + + _request_send_result(req, ret); + + return ret; +} + +static int __validate_widget_caller(request_h req) +{ + bundle *kb = req->kb; + char *appid = NULL; + struct appinfo *target; + const char *target_pkgid; + app_status_h caller_status; + const char *caller_pkgid; + + if (req->uid < REGULAR_UID_MIN) { + _D("bypass caller package check"); + return 0; + } + + bundle_get_str(kb, AUL_K_APPID, &appid); + if (!appid) { + _E("no appid provided"); + return -1; + } + + target = _appinfo_find(req->uid, appid); + if (!target) { + _E("can not find appinfo of %s", appid); + return -1; + } + + target_pkgid = _appinfo_get_value(target, AIT_PKGID); + if (!target_pkgid) { + _E("can not get pkgid %s", target_pkgid); + return -1; + } + + caller_status = _app_status_find(req->pid); + if (!caller_status) + return 0; /* not app? */ + + caller_pkgid = _app_status_get_pkgid(caller_status); + if (!caller_pkgid) { + _E("can not get caller pkgid"); + return -1; + } + + _D("compare pkgid %s:%s", caller_pkgid, target_pkgid); + if (strcmp(caller_pkgid, target_pkgid) == 0) + return 0; + + return -1; +} + +static int __dispatch_widget_get_content(request_h req) +{ + int handles[2] = {0,}; + struct iovec vec[3]; + int msglen = 0; + char buffer[1024]; + int ret; + bundle *kb = req->kb; + struct timeval tv; + int pid; + char *widget_id = NULL; + char *instance_id = NULL; + + if (__validate_widget_caller(req) < 0) { + _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) { + _E("can not find widget"); + _request_send_result(req, -ENOENT); + return -1; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 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; + } + + tv.tv_sec = 5; + tv.tv_usec = 0; + + ret = setsockopt(handles[1], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + if (ret < 0) { + _E("cannot set SO_RCVTIMEO for socket %d", handles[0]); + _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, _request_get_target_uid(req), req->cmd, + req->kb, AUL_SOCK_ASYNC); + + msglen = __send_message(ret, vec, 1, &(handles[0]), 1); + if (msglen < 0) { + _E("Error[%d]: while sending message to widget", -msglen); + _request_send_result(req, -1); + ret = -1; + goto out; + } + + msglen = __send_message(req->clifd, vec, 1, &(handles[1]), 1); + if (msglen < 0) { + _E("Error[%d]: while sending message to caller", -msglen); + _request_send_result(req, -1); + ret = -1; + } + +out: + close(handles[0]); + close(handles[1]); + + return ret; +} + +static int __dispatch_widget_list(request_h req) +{ + bundle *kb = req->kb; + char *widget_id = NULL; + int ret; + + if (__validate_widget_caller(req) < 0) { + _request_send_result(req, -EILLEGALACCESS); + return -1; + } + + bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id); + if (!widget_id) { + _request_send_result(req, -EINVAL); + return -1; + } + + ret = _widget_list(widget_id, req); + + return ret; +} + +static int __dispatch_widget_update(request_h req) +{ + bundle *kb = _request_get_bundle(req); + char *widget_id = NULL; + int ret; + + if (__validate_widget_caller(req) < 0) { + _request_send_result(req, -EILLEGALACCESS); + return -1; + } + + bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id); + if (!widget_id) { + _request_send_result(req, -EINVAL); + return -1; + } + + /* update will pass bundle by app_control */ + req->cmd = APP_START_ASYNC; + + ret = _widget_update(widget_id, req); + if (ret < 0) + return -1; + + return 0; +} + +static int __dispatch_widget_count(request_h req) +{ + bundle *kb = req->kb; + char *widget_id = NULL; + int count; + + bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id); + if (!widget_id) { + _request_send_result(req, -EINVAL); + return -1; + } + count = _widget_count(widget_id, _request_get_uid(req)); + _D("dispatch widget count %d", count); + _request_send_result(req, count); + + 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); + 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 ret; +} + +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_add_app_screen(request_h req) +{ + uid_t uid = _request_get_target_uid(req); + int pid = _request_get_pid(req); + bundle *b = _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); + _D("pid(%d), surf(%d), instance_id(%s), result(%d)", + pid, surf, instance_id, ret); + + return 0; +} + +static int __dispatch_remove_app_screen(request_h req) +{ + uid_t uid = _request_get_target_uid(req); + int pid = _request_get_pid(req); + bundle *b = _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); + _D("pid(%d), instance_id(%s), result(%d)", + pid, instance_id, ret); + + return 0; +} + +static int __dispatch_app_update_requested(request_h req) +{ + uid_t uid = _request_get_target_uid(req); + int caller_pid = _request_get_pid(req); + bundle *b = _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); + _D("appid(%s), instance_id(%s), caller_pid(%d), result(%d)", + appid, instance_id, caller_pid, ret); + + return 0; +} + +static int __dispatch_add_screen_viewer(request_h req) +{ + uid_t uid = _request_get_target_uid(req); + int pid = _request_get_pid(req); + bundle *b = _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); + _D("pid(%d), screen_type(%d), private(%d), result(%d)", + pid, screen_type, priv, ret); + + return 0; +} + +static int __dispatch_remove_screen_viewer(request_h req) +{ + uid_t uid = _request_get_target_uid(req); + int pid = _request_get_pid(req); + bundle *b = _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); + _D("pid(%d), screen_type(%d), private(%d), result(%d)", + pid, screen_type, priv, 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 __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 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 int __dispatch_app_startup_signal(request_h req) +{ + int pid = _request_get_pid(req); + app_status_h app_status; + struct pending_item *item; + struct reply_info *info; + GList *iter; + + _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); + + 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; + } + + item->timer = g_timeout_add(PENDING_REQUEST_TIMEOUT, + __timeout_pending_item, item); + + iter = g_list_first(item->reply_list); + while (iter) { + info = (struct reply_info *)iter->data; + if (info && info->rua) { + g_timeout_add(1500, __add_history_handler, info->rua); + info->rua = NULL; + } + iter = g_list_next(iter); + } + + return 0; +} + +static int __dispatch_app_window_attach(request_h req) +{ + bundle *b = _request_get_bundle(req); + const char *parent_appid; + const char *child_appid; + int ret; + uid_t uid = _request_get_target_uid(req); + + if (!b) { + _E("Invalid bundle"); + _request_send_result(req, -1); + return -1; + } + + parent_appid = bundle_get_val(b, AUL_K_PARENT_APPID); + if (!parent_appid) { + _E("Invalid parameters"); + _request_send_result(req, -1); + return -1; + } + + child_appid = bundle_get_val(b, AUL_K_CHILD_APPID); + if (!child_appid) { + _E("Invalid parameters"); + _request_send_result(req, -1); + return -1; + } + + ret = _app_group_attach(parent_appid, child_appid, uid); + _request_send_result(req, ret); + + return 0; +} + +static int __dispatch_app_window_detach(request_h req) +{ + bundle *b = _request_get_bundle(req); + const char *child_appid; + int ret; + uid_t uid = _request_get_target_uid(req); + + if (!b) { + _E("Invalid bundle"); + _request_send_result(req, -1); + return -1; + } + + child_appid = bundle_get_val(b, AUL_K_CHILD_APPID); + if (!child_appid) { + _E("Invalid parameters"); + _request_send_result(req, -1); + return -1; + } + + ret = _app_group_detach(child_appid, uid); + _request_send_result(req, ret); + + return 0; +} + +static int __dispatch_app_notify_exit(request_h req) +{ + int pid = _request_get_pid(req); + int ret; + app_status_h app_status; + + 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; + } + + ret = _app_status_set_is_exit_notified(app_status, true); + _D("[APP_NOTIFY_EXIT] result(%d)", ret); + + return 0; +} + +static int __dispatch_app_get_appid_by_surface_id(request_h req) +{ + uid_t uid = _request_get_target_uid(req); + bundle *b = _request_get_bundle(req); + unsigned int *surf = NULL; + const char *appid; + size_t size; + bundle *ret_b; + + if (b == NULL) { + _request_send_result(req, -1); + return -1; + } + + bundle_get_byte(b, "__AUL_SC_SURFACE__", (void **)&surf, &size); + if (surf == NULL) { + _E("Failed to get surface"); + _request_send_result(req, -1); + return -1; + } + + appid = _screen_connector_get_appid_by_surface_id(*surf, uid); + if (appid == NULL) { + _E("Failed to get appid"); + _request_send_result(req, -1); + return -1; + } + + ret_b = bundle_create(); + if (ret_b == NULL) { + _E("Out of memory"); + _request_send_result(req, -1); + return -1; + } + + bundle_add_str(ret_b, AUL_K_APPID, appid); + aul_sock_send_bundle_with_fd(_request_remove_fd(req), + _request_get_cmd(req), ret_b, AUL_SOCK_NOREPLY); + bundle_free(ret_b); + + return 0; +} + +static int __dispatch_app_get_instance_id_by_surface_id(request_h req) +{ + uid_t uid = _request_get_target_uid(req); + bundle *b = _request_get_bundle(req); + unsigned int *surf = NULL; + const char *instance_id; + size_t size; + bundle *ret_b; + + if (b == NULL) { + _request_send_result(req, -1); + return -1; + } + + bundle_get_byte(b, "__AUL_SC_SURFACE__", (void **)&surf, &size); + if (surf == NULL) { + _E("Failed to get surface"); + _request_send_result(req, -1); + return -1; + } + + instance_id = _screen_connector_get_instance_id_by_surface_id(*surf, + uid); + if (instance_id == NULL) { + _E("Failed to get instance_id"); + _request_send_result(req, -1); + return -1; + } + + ret_b = bundle_create(); + if (ret_b == NULL) { + _E("Out of memory"); + _request_send_result(req, -1); + return -1; + } + + bundle_add_str(ret_b, AUL_K_INSTANCE_ID, instance_id); + aul_sock_send_bundle_with_fd(_request_remove_fd(req), + _request_get_cmd(req), ret_b, AUL_SOCK_NOREPLY); + bundle_free(ret_b); + + return 0; +} + +static int __dispatch_update_screen_viewer_status(request_h req) +{ + uid_t uid = _request_get_target_uid(req); + int pid = _request_get_pid(req); + bundle *b = _request_get_bundle(req); + const char *val; + aul_screen_status_e status; + unsigned int surf; + int r; + + if (b == NULL) { + _request_send_result(req, -1); + return -1; + } + + val = bundle_get_val(b, "__AUL_SC_VIEWER_STATUS__"); + if (val == NULL || !isdigit(*val)) { + _E("Failed to get viewer status"); + _request_send_result(req, -1); + return -1; + } + + status = atoi(val); + + val = bundle_get_val(b, AUL_K_WID); + if (val == NULL || !isdigit(*val)) { + _E("Failed to get surface id"); + _request_send_result(req, -1); + return -1; + } + + surf = strtoul(val, NULL, 10); + + r = _screen_connector_update_screen_viewer_status(pid, status, + surf, uid); + _request_send_result(req, r); + + return 0; +} + +static int __dispatch_widget_running_info(request_h req) +{ + return _widget_send_running_info(req); +} + +static app_cmd_dispatch_func dispatch_table[APP_CMD_MAX] = { + [APP_GET_DC_SOCKET_PAIR] = __dispatch_get_dc_socket_pair, + [APP_GET_MP_SOCKET_PAIR] = __dispatch_get_mp_socket_pair, + [APP_START] = __dispatch_app_start, + [APP_OPEN] = __dispatch_app_start, + [APP_RESUME] = __dispatch_app_start, + [APP_RESUME_BY_PID] = __dispatch_app_process_by_pid, + [APP_TERM_BY_PID] = __dispatch_app_term, + [APP_TERM_BY_PID_WITHOUT_RESTART] = __dispatch_app_term_async, + [APP_RESULT] = __dispatch_app_result, + [APP_START_RES] = __dispatch_app_start, + [APP_CANCEL] = __dispatch_app_result, + [APP_KILL_BY_PID] = __dispatch_app_term, + [APP_UPDATE_RUA_STAT] = __dispatch_update_rua_stat, + [APP_ADD_HISTORY] = __dispatch_add_history, + [APP_REMOVE_HISTORY] = __dispatch_remove_history, + [APP_RUNNING_INFO] = __dispatch_app_running_info, + [APP_RUNNING_INFO_RESULT] = NULL, + [APP_IS_RUNNING] = __dispatch_app_is_running, + [APP_GET_APPID_BYPID] = __dispatch_app_get_appid_by_pid, + [APP_GET_PKGID_BYPID] = __dispatch_app_get_pkgid_by_pid, + [APP_GET_INFO_OK] = NULL, + [APP_GET_INFO_ERROR] = NULL, + [APP_KEY_EVENT] = NULL, + [APP_KEY_RESERVE] = __dispatch_legacy_command, + [APP_KEY_RELEASE] = __dispatch_legacy_command, + [APP_STATUS_UPDATE] = __dispatch_app_status_update, + [APP_RUNNING_LIST_UPDATE] = __dispatch_legacy_command, + [APP_TERM_REQ_BY_PID] = __dispatch_app_process_by_pid, + [APP_TERM_BY_PID_ASYNC] = __dispatch_app_term_async, + [APP_TERM_BGAPP_BY_PID] = __dispatch_app_term, + [APP_PAUSE] = __dispatch_app_pause, + [APP_PAUSE_BY_PID] = __dispatch_app_process_by_pid, + [APP_GROUP_GET_WINDOW] = __dispatch_app_group_get_window, + [APP_GROUP_SET_WINDOW] = __dispatch_app_group_set_window, + [APP_GROUP_GET_FG] = __dispatch_app_group_get_fg_flag, + [APP_GROUP_GET_LEADER_PID] = __dispatch_app_group_get_leader_pid, + [APP_GROUP_GET_LEADER_PIDS] = __dispatch_app_group_get_leader_pids, + [APP_GROUP_GET_GROUP_PIDS] = __dispatch_app_group_get_group_pids, + [APP_GROUP_GET_IDLE_PIDS] = __dispatch_app_group_get_idle_pids, + [APP_GROUP_LOWER] = __dispatch_app_group_lower, + [APP_GROUP_CLEAR_TOP] = __dispatch_app_group_clear_top, + [APP_GROUP_ACTIVATE_BELOW] = __dispatch_app_group_activate_below, + [APP_GROUP_ACTIVATE_ABOVE] = __dispatch_app_group_activate_above, + [APP_GET_STATUS] = __dispatch_app_get_status, + [APP_ADD_LOADER] = __dispatch_app_add_loader, + [APP_REMOVE_LOADER] = __dispatch_app_remove_loader, + [APP_GET_PID] = __dispatch_app_is_running, + [AMD_RELOAD_APPINFO] = __dispatch_amd_reload_appinfo, + [LAUNCHPAD_DEAD_SIGNAL] = __dispatch_launchpad_dead_signal, + [APP_COM_CREATE] = __dispatch_app_com_create, + [APP_COM_JOIN] = __dispatch_app_com_join, + [APP_COM_SEND] = __dispatch_app_com_send, + [APP_COM_LEAVE] = __dispatch_app_com_leave, + [WIDGET_ADD] = __dispatch_widget_add_del, + [WIDGET_DEL] = __dispatch_widget_add_del, + [WIDGET_LIST] = __dispatch_widget_list, + [WIDGET_UPDATE] = __dispatch_widget_update, + [WIDGET_COUNT] = __dispatch_widget_count, + [WIDGET_GET_CONTENT] = __dispatch_widget_get_content, + [APP_REGISTER_PID] = __dispatch_app_register_pid, + [APP_ALL_RUNNING_INFO] = __dispatch_app_all_running_info, + [APP_SET_APP_CONTROL_DEFAULT_APP] = + __dispatch_app_set_app_control_default_app, + [APP_UNSET_APP_CONTROL_DEFAULT_APP] = + __dispatch_app_unset_app_control_default_app, + [APP_START_ASYNC] = __dispatch_app_start, + [APP_SET_PROCESS_GROUP] = __dispatch_app_set_process_group, + [APP_PREPARE_CANDIDATE_PROCESS] = + __dispatch_app_prepare_candidate_process, + [APP_TERM_BY_PID_SYNC] = __dispatch_app_term_sync, + [APP_GET_STATUS_BY_APPID] = __dispatch_app_get_status_by_appid, + [APP_GET_LAST_CALLER_PID] = __dispatch_app_get_last_caller_pid, + [APP_TERM_BY_PID_SYNC_WITHOUT_RESTART] = + __dispatch_app_term_sync_without_restart, + [APP_RESUME_BY_PID_ASYNC] = __dispatch_app_process_by_pid, + [APP_SET_ALIAS_APPID] = __dispatch_app_set_alias_appid, + [APP_UNSET_ALIAS_APPID] = __dispatch_app_unset_alias_appid, + [APP_ENABLE_ALIAS_INFO] = __dispatch_app_enable_alias_info, + [APP_DISABLE_ALIAS_INFO] = __dispatch_app_disable_alias_info, + [ADD_APP_SCREEN] = __dispatch_add_app_screen, + [REMOVE_APP_SCREEN] = __dispatch_remove_app_screen, + [APP_UPDATE_REQUESTED] = __dispatch_app_update_requested, + [ADD_SCREEN_VIEWER] = __dispatch_add_screen_viewer, + [REMOVE_SCREEN_VIEWER] = __dispatch_remove_screen_viewer, + [LAUNCHPAD_LAUNCH_SIGNAL] = __dispatch_launchpad_launch_signal, + [APP_RUNNING_INSTANCE_INFO] = __dispatch_app_running_instance_info, + [APP_GET_INSTANCE_ID_BYPID] = __dispatch_app_get_instance_id_by_pid, + [APP_GET_APPID_FROM_CACHE] = __dispatch_app_get_appid_from_cache, + [APP_SET_CACHE] = __dispatch_app_set_cache, + [APP_INVALIDATE_CACHE] = __dispatch_app_invalidate_cache, + [APP_STARTUP_SIGNAL] = __dispatch_app_startup_signal, + [APP_WINDOW_ATTACH] = __dispatch_app_window_attach, + [APP_WINDOW_DETACH] = __dispatch_app_window_detach, + [APP_START_RES_ASYNC] = __dispatch_app_start, + [APP_NOTIFY_EXIT] = __dispatch_app_notify_exit, + [APP_GET_APPID_BY_SURFACE_ID] = __dispatch_app_get_appid_by_surface_id, + [APP_GET_INSTANCE_ID_BY_SURFACE_ID] = + __dispatch_app_get_instance_id_by_surface_id, + [UPDATE_SCREEN_VIEWER_STATUS] = __dispatch_update_screen_viewer_status, + [WIDGET_RUNNING_INFO] = __dispatch_widget_running_info, +}; + +static void __free_reply_info(gpointer data) +{ + struct reply_info *reply = (struct reply_info *)data; + + if (reply == NULL) + return; + + if (reply->rua) + __free_rua_stat_pkt(reply->rua); + if (reply->clifd) + close(reply->clifd); + if (reply->timer) + g_source_remove(reply->timer); + free(reply); +} + +static struct reply_info *__create_reply_info(guint interval, pid_t pid, + int result, int cmd, int clifd, rua_stat_pkt_t *rua) +{ + 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->rua = rua; + + 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_reply(gpointer data) +{ + struct reply_info *reply = (struct reply_info *)data; + struct pending_item *item; + + if (reply == NULL) + return FALSE; + + item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(reply->pid)); + if (item) + item->reply_list = g_list_remove(item->reply_list, reply); + + _send_result_to_client(reply->clifd, reply->result); + reply->clifd = 0; + reply->timer = 0; + __free_reply_info(reply); + + return FALSE; +} + +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; + + if (req == NULL) + return FALSE; + + if (req->cmd < 0 || req->cmd >= APP_CMD_MAX) { + __free_request(req); + return FALSE; + } + + if (dispatch_table[req->cmd]) { + if (dispatch_table[req->cmd](req) != 0) + _E("callback returns FALSE : %d", req->cmd); + } else { + _E("Invalid request or not supported command"); + } + + __free_request(req); + + return FALSE; +} + +int _request_usr_init(uid_t uid) +{ + GList *iter; + request_h req; + int r; + struct pending_item *item; + + 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 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); + if (ret < 0) { + _E("request has been denied by cynara"); + ret = -EILLEGALACCESS; + _request_send_result(req, ret); + __free_request(req); + 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; +} + +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_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; +} + +static void __free_socket_pair(gpointer data) +{ + int *handles = (int *)data; + + if (handles[0] > 0) + close(handles[0]); + if (handles[1] > 0) + close(handles[1]); + free(handles); +} + +int _request_init(void) +{ + _D("request init"); + __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"); + _request_fini(); + return -1; + } + + 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; + } + + 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 (__dc_socket_pair_hash) { + g_hash_table_destroy(__dc_socket_pair_hash); + __dc_socket_pair_hash = NULL; + } +} diff --git a/src/amd_rua.c b/src/amd_rua.c new file mode 100644 index 0000000..58a729b --- /dev/null +++ b/src/amd_rua.c @@ -0,0 +1,437 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_rua.h" +#include "amd_app_status.h" +#include "amd_app_group.h" +#include "amd_inotify.h" + +#define PATH_RUN "/run" +#define FILE_E_IMG ".e-img" +#define PATH_RUN_E_IMG PATH_RUN "/" FILE_E_IMG + +struct rua_info_s { + uid_t uid; + char *appid; + char *app_path; + char *instance_id; + char *image_path; + unsigned int surf; +}; + +static int __dir_wd; +static int __img_wd; +static GHashTable *__rua_tbl; + +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) { + _E("Out of memory"); + return NULL; + } + + info->appid = strdup(appid); + if (info->appid == NULL) { + _E("Out of memory"); + __destroy_rua_info(info); + return NULL; + } + + info->app_path = strdup(app_path); + if (info->app_path == NULL) { + _E("Out of memory"); + __destroy_rua_info(info); + return NULL; + } + + if (instance_id) { + info->instance_id = strdup(instance_id); + if (info->instance_id == NULL) { + _E("Out of memory"); + __destroy_rua_info(info); + return NULL; + } + } + + info->uid = uid; + + return info; +} + +int _rua_update_screen_info(int pid, unsigned int surf) +{ + struct rua_info_s *info; + int leader_pid; + + if (__rua_tbl == NULL) + return -1; + + leader_pid = _app_group_get_leader_pid(pid); + if (leader_pid > 0) + pid = leader_pid; + + info = (struct rua_info_s *)g_hash_table_lookup(__rua_tbl, + GINT_TO_POINTER(pid)); + if (info == NULL) + return -1; + + info->surf = surf; + + return 0; +} + +int _rua_add_info(int pid, bool new_instance) +{ + struct rua_info_s *info; + 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 = _app_status_find(pid); + if (app_status == NULL) + return -1; + + appid = _app_status_get_appid(app_status); + app_path = _app_status_get_app_path(app_status); + uid = _app_status_get_uid(app_status); + + if (new_instance) + instance_id = _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; +} + +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; +} + +int _rua_delete_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 surf = 0; + int num = -1; + char buf[PATH_MAX]; + struct rua_info_s *info; + int leader_pid; + + sscanf(img, "win_%d_%u-%d.png", &pid, &surf, &num); + if (pid <= 0) + return; + + snprintf(buf, sizeof(buf), "%s/%s", PATH_RUN_E_IMG, img); + + leader_pid = _app_group_get_leader_pid(pid); + if (leader_pid > 0) + pid = leader_pid; + + info = (struct rua_info_s *)g_hash_table_lookup(__rua_tbl, + GINT_TO_POINTER(pid)); + if (info == NULL || (info->surf != 0 && info->surf != surf)) { + 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) + _W("Failed to update image path - appid(%s)", info->appid); + + info->image_path = strdup(buf); + if (info->image_path == NULL) + _E("Out of memory"); + + if (info->surf == 0) + info->surf = surf; +} + +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); + _D("%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 = _inotify_add_watch(PATH_RUN_E_IMG, IN_CREATE, + __img_monitor_cb, NULL); + if (__img_wd < 0) + _E("Failed to add inotify watch"); + else + __find_imgs(); + + __dir_wd = 0; + return false; + } + + return true; +} + +int _rua_usr_init(uid_t uid) +{ + int r; + + r = rua_usr_db_delete_history(NULL, uid); + if (r < 0) { + _E("Failed to delete rua history - uid(%u)", uid); + return -1; + } + + return 0; +} + +void _rua_usr_fini(uid_t uid) +{ + if (__rua_tbl == NULL) + return; + + g_hash_table_foreach_remove(__rua_tbl, + __foreach_remove_by_uid, GUINT_TO_POINTER(uid)); +} + +int _rua_init(void) +{ + _D("[RUA] init"); + + if (access(PATH_RUN_E_IMG, F_OK) == 0) { + __img_wd = _inotify_add_watch(PATH_RUN_E_IMG, IN_CREATE, + __img_monitor_cb, NULL); + if (__img_wd < 0) + return -1; + + __find_imgs(); + } else { + __dir_wd = _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) { + _E("Failed to create rua table"); + return -1; + } + + return 0; +} + +void _rua_fini(void) +{ + _D("[RUA] finish"); + + if (__rua_tbl) { + g_hash_table_destroy(__rua_tbl); + __rua_tbl = NULL; + } + + if (__dir_wd > 0) + _inotify_rm_watch(__dir_wd); + if (__img_wd > 0) + _inotify_rm_watch(__img_wd); +} diff --git a/src/amd_screen_connector.c b/src/amd_screen_connector.c new file mode 100644 index 0000000..3aa7ba9 --- /dev/null +++ b/src/amd_screen_connector.c @@ -0,0 +1,956 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_app_group.h" +#include "amd_app_status.h" +#include "amd_app_com.h" +#include "amd_suspend.h" +#include "amd_screen_connector.h" + +#define SUSPEND_INTERVAL 5 /* sec */ + +struct app_screen_s { + char *appid; + char *instance_id; + int pid; + uid_t uid; + unsigned int surf; + int screen_type; + int caller_pid; + GList *viewer_list; +}; + +struct viewer_info_s { + int pid; + int screen_type; + bool priv; + unsigned int ref; + aul_screen_status_e status; + GList *watch_list; +}; + +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) { + _E("out of memory"); + return NULL; + } + + app_screen->appid = strdup(appid); + if (app_screen->appid == NULL) { + _E("out of memory"); + free(app_screen); + return NULL; + } + + app_screen->instance_id = strdup(instance_id); + if (app_screen->instance_id == NULL) { + _E("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; + struct viewer_info_s *viewer_info; + GList *iter; + + if (app_screen == NULL) + return; + + if (app_screen->viewer_list) { + iter = app_screen->viewer_list; + while (iter) { + viewer_info = (struct viewer_info_s *)iter->data; + viewer_info->watch_list = g_list_remove( + viewer_info->watch_list, app_screen); + iter = g_list_next(iter); + } + g_list_free(app_screen->viewer_list); + } + + 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 void __destroy_viewer_info(struct viewer_info_s *viewer_info) +{ + struct app_screen_s *app_screen; + GList *iter; + + if (viewer_info == NULL) + return; + + if (viewer_info->watch_list) { + iter = viewer_info->watch_list; + while (iter) { + app_screen = (struct app_screen_s *)iter->data; + app_screen->viewer_list = g_list_remove( + app_screen->viewer_list, viewer_info); + iter = g_list_next(iter); + } + g_list_free(viewer_info->watch_list); + } + + free(viewer_info); +} + +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) { + _E("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) { + _E("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) { + _E("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) { + _E("out of memory"); + return; + } + + snprintf(endpoint, sizeof(endpoint), "app_screen_event:%u:%d", + viewer_info->ref, viewer_info->pid); + _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 gint __compare_app_screen_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 (strcmp(app_screen->instance_id, instance_id) == 0) + return 0; + + return -1; +} + +unsigned int _screen_connector_get_surface_id(const char *instance_id, + uid_t uid) +{ + struct user_info_s *user_info; + struct app_screen_s *app_screen; + GList *found; + + if (instance_id == NULL) + return 0; + + user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid)); + if (user_info == NULL) + return 0; + + found = g_list_find_custom(user_info->app_screen_list, + instance_id, __compare_app_screen_instance_id); + if (found) { + app_screen = (struct app_screen_s *)found->data; + return app_screen->surf; + } + + return 0; +} + +static int __get_screen_type(int app_type) +{ + switch (app_type) { + case AT_UI_APP: + return AUL_SCREEN_TYPE_UI; + case AT_WIDGET_APP: + return AUL_SCREEN_TYPE_WIDGET; + case 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_get_group_pids(pid, &cnt, &pids); + for (i = 0; i < cnt; ++i) { + wid = (unsigned int)_app_group_get_window(pids[i]); + if (wid == surf) { + _D("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 = _suspend_update_status(pid, SUSPEND_STATUS_INCLUDE); + _D("pid(%d), result(%d)", pid, ret); + + return FALSE; +} + +static gint __compare_app_screen_surf(gconstpointer a, gconstpointer b) +{ + struct app_screen_s *app_screen = (struct app_screen_s *)a; + unsigned int surf = GPOINTER_TO_UINT(b); + + if (app_screen->surf == surf) + return 0; + + return -1; +} + +const char *_screen_connector_get_appid_by_surface_id(unsigned int surf, + uid_t uid) +{ + struct user_info_s *user_info; + struct app_screen_s *app_screen; + GList *found; + + user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid)); + if (user_info == NULL) + return NULL; + + found = g_list_find_custom(user_info->app_screen_list, + GUINT_TO_POINTER(surf), __compare_app_screen_surf); + if (found) { + app_screen = (struct app_screen_s *)found->data; + return app_screen->appid; + } + + return NULL; +} + +const char *_screen_connector_get_instance_id_by_surface_id(unsigned int surf, + uid_t uid) +{ + struct user_info_s *user_info; + struct app_screen_s *app_screen; + GList *found; + + user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid)); + if (user_info == NULL) + return NULL; + + found = g_list_find_custom(user_info->app_screen_list, + GUINT_TO_POINTER(surf), __compare_app_screen_surf); + if (found) { + app_screen = (struct app_screen_s *)found->data; + return app_screen->instance_id; + } + + return NULL; +} + +/* TODO: The provider_appid should be provider_instance_id. */ +static int __send_viewer_visibility_to_provider(const char *provider_appid, + aul_screen_status_e status, int viewer_pid, uid_t viewer_uid) +{ + bundle *b; + + b = bundle_create(); + if (b == NULL) { + _E("out of memory"); + return -1; + } + + bundle_add_byte(b, "__AUL_SC_VIEWER_STATUS__", + &status, sizeof(aul_screen_status_e)); + _app_com_send(provider_appid, viewer_pid, b, viewer_uid); + bundle_free(b); + _D("send viewer status to %s(%d)", provider_appid, status); + + return 0; +} + +static gint __compare_viewer_pid(gconstpointer a, gconstpointer b) +{ + struct viewer_info_s *viewer_info = (struct viewer_info_s *)a; + int pid = GPOINTER_TO_INT(b); + + if (viewer_info->pid == pid) + return 0; + + return -1; +} + +int _screen_connector_update_screen_viewer_status(int pid, int status, + unsigned int surf, uid_t uid) +{ + struct user_info_s *user_info; + struct app_screen_s *app_screen; + struct viewer_info_s *viewer_info; + bool send_pause = true; + GList *found; + GList *iter; + + user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid)); + if (user_info == NULL) + return -1; + + found = g_list_find_custom(user_info->screen_viewer_list, + GINT_TO_POINTER(pid), __compare_viewer_pid); + if (found == NULL) + return -1; + + viewer_info = (struct viewer_info_s *)found->data; + viewer_info->status = status; + + found = g_list_find_custom(user_info->app_screen_list, + GUINT_TO_POINTER(surf), __compare_app_screen_surf); + if (found == NULL) + return -1; + + app_screen = (struct app_screen_s *)found->data; + found = g_list_find(app_screen->viewer_list, viewer_info); + if (!found) { + app_screen->viewer_list = g_list_append(app_screen->viewer_list, + viewer_info); + } + + found = g_list_find(viewer_info->watch_list, app_screen); + if (!found) { + viewer_info->watch_list = g_list_append(viewer_info->watch_list, + app_screen); + } + + if (status == AUL_SCREEN_STATUS_PAUSE) { + iter = app_screen->viewer_list; + while (iter) { + viewer_info = (struct viewer_info_s *)iter->data; + if (viewer_info->status != AUL_SCREEN_STATUS_PAUSE) { + /* + * Every veiwer must be paused to send + * viewer pause event to provider + */ + send_pause = false; + break; + } + iter = g_list_next(iter); + } + if (send_pause) { + __send_viewer_visibility_to_provider(app_screen->appid, + status, pid, uid); + } + } else if (status == AUL_SCREEN_STATUS_RESUME) { + __send_viewer_visibility_to_provider(app_screen->appid, status, + pid, uid); + } else { + _W("Unknown status(%d)", status); + } + + return 0; +} + +int _screen_connector_send_update_request(const char *appid, + const char *instance_id, uid_t uid) +{ + 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 = _app_status_find_by_instance_id(appid, + instance_id, uid); + } else { + app_status = _app_status_find_by_appid(appid, uid); + } + if (app_status == NULL) + return -1; + if (_app_status_get_status(app_status) == STATUS_DYING) + return -1; + if (_app_status_get_app_type(app_status) != AT_UI_APP) + return -1; + if (_app_status_is_home_app(app_status)) + return -1; + if (instance_id == NULL) { + instance_id = _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 = _suspend_update_status(pid, 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) { + _E("Failed to send the update request"); + _suspend_update_status(pid, SUSPEND_STATUS_INCLUDE); + return -1; + } + g_timeout_add_seconds(SUSPEND_INTERVAL, __suspend_timer, + GINT_TO_POINTER(pid)); + _D("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) +{ + 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(pid); + if (leader_pid > 0) + pid = leader_pid; + + app_status = _app_status_find(pid); + if (app_status == NULL) { + _W("Failed to find app status info - pid(%d), uid(%d)", + pid, uid); + return -1; + } + + if (_app_status_is_home_app(app_status)) + return 0; + + appid = _app_status_get_appid(app_status); + if (instance_id == NULL) { + instance_id = _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) { + _D("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 = _app_status_get_org_caller_pid(app_status); + app_type = _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); + _D("pid(%d), appid(%s), surf(%d), uid(%d)", pid, appid, surf, uid); + + return 0; +} + +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; + 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(pid); + if (leader_pid > 0) + pid = leader_pid; + + app_status = _app_status_find(pid); + if (app_status == NULL) { + _W("Failed to find app status info - pid(%d), uid(%d)", + pid, uid); + return -1; + } + + if (_app_status_is_home_app(app_status)) + return 0; + + if (instance_id == NULL) { + instance_id = _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); + _D("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; +} + +int _screen_connector_update_app_screen(int pid, unsigned int surf, uid_t uid) +{ + 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; + + 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(pid); + if (leader_pid > 0) + pid = leader_pid; + + app_status = _app_status_find(pid); + if (app_status == NULL) { + _W("Failed to find app status info - pid(%d), uid(%d)", + pid, uid); + return -1; + } + + if (_app_status_is_home_app(app_status)) + return 0; + + appid = _app_status_get_appid(app_status); + instance_id = _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); + _D("pid(%d), appid(%s), surf(%d), uid(%d)", pid, appid, surf, uid); + + return 0; +} + +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) { + _D("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); +} + +int _screen_connector_add_screen_viewer(int pid, int screen_type, + bool priv, unsigned int ref, uid_t uid) +{ + app_status_h app_status; + struct user_info_s *user_info; + struct viewer_info_s *viewer_info; + GList *list; + + app_status = _app_status_find(pid); + if (app_status == NULL) { + _W("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) { + _W("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) { + _D("Already exists"); + __destroy_viewer_info(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); + _D("pid(%d), screen_type(%d), private(%d), ref(%u), uid(%d)", + pid, screen_type, priv, ref, uid); + + return 0; +} + +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) { + _W("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); + __destroy_viewer_info(viewer_info); + } + } + + _D("pid(%d), screen_type(%d), private(%d), ref(%u) uid(%d)", + pid, screen_type, priv, ref, uid); + + return 0; +} + +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) { + _W("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); + __destroy_viewer_info(viewer_info); + } + } + + return 0; +} + +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) { + _E("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; +} + +void _screen_connector_usr_fini(uid_t uid) +{ + g_hash_table_remove(user_table, GUINT_TO_POINTER(uid)); +} + +int _screen_connector_init(void) +{ + _D("screen connector init"); + + user_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, __destroy_user_info); + if (user_table == NULL) { + _E("Failed to create user table"); + return -1; + } + + return 0; +} + +void _screen_connector_fini(void) +{ + _D("screen connector fini"); + + if (user_table) + g_hash_table_destroy(user_table); +} diff --git a/src/amd_share.c b/src/amd_share.c new file mode 100644 index 0000000..26b0742 --- /dev/null +++ b/src/amd_share.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_appinfo.h" +#include "amd_app_status.h" +#include "amd_share.h" +#include "aul_svc_priv_key.h" + +#define LEGACY_APP_PATH "/opt/usr/apps/" + +struct shared_info_main_s { + char *appid; + uid_t uid; + shared_info_t *shared_info; +}; + +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) { + _E("failed to stat file to share (%s, %d)", path, errno); + return -1; + } + + if (!S_ISREG(path_stat.st_mode)) { + _E("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; + 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 = _app_status_find(caller_pid); + appid = _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; + app_status_h app_status; + + owner_pid = __get_owner_pid(caller_pid, kb); + owner_pid = getpgid(owner_pid); /* for webapp */ + app_status = _app_status_find(owner_pid); + owner_appid = _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) + return NULL; + + h->shared_info = malloc(sizeof(shared_info_t)); + if (h->shared_info == NULL) { + free(h); + return NULL; + } + + ret = security_manager_private_sharing_req_new(&h->shared_info->handle); + if (ret != SECURITY_MANAGER_SUCCESS) { + free(h->shared_info); + free(h); + return NULL; + } + + h->shared_info->owner_appid = strdup(owner_appid); + h->appid = strdup(appid); + 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; + const struct appinfo *ai; + int ret; + + ret = bundle_get_str(kb, AUL_SVC_K_URI, &path); + if (ret != BUNDLE_ERROR_NONE) + return paths; + + if (!path) { + _D("path was null"); + return paths; + } + + if (strncmp(path, "file://", 7) == 0) { + path = &path[7]; + } else { + _E("file wasn't started with file://"); + return paths; + } + + ai = _appinfo_find(uid, owner_appid); + pkgid = _appinfo_get_value(ai, AIT_PKGID); + + path = __convert_legacy_path(path, uid); + if (__can_share(path, pkgid, uid) != 0) { + _E("__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; + const struct appinfo *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) { + _E("path_array was null"); + return paths; + } + + ai = _appinfo_find(uid, owner_appid); + if (ai == NULL) { + _E("appinfo is NULL"); + return paths; + } + pkgid = _appinfo_get_value(ai, AIT_PKGID); + if (pkgid == NULL) { + _E("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; + const struct appinfo *ai = NULL; + char *path_str; + + switch (type) { + case BUNDLE_TYPE_STR: + bundle_get_str(kb, AUL_SVC_DATA_PATH, &path); + if (!path) { + _E("path was null"); + break; + } + + ai = _appinfo_find(uid, owner_appid); + pkgid = _appinfo_get_value(ai, AIT_PKGID); + if (pkgid == NULL) { + _E("pkgid was null"); + break; + } + + path = __convert_legacy_path(path, uid); + if (__can_share(path, pkgid, uid) != 0) { + _E("__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) { + _E("path_array was null"); + break; + } + + ai = _appinfo_find(uid, owner_appid); + pkgid = _appinfo_get_value(ai, AIT_PKGID); + if (pkgid == NULL) { + _E("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_malloc(sizeof(char *) * (len + 1)); + if (array == NULL) { + _E("out of memory"); + return NULL; + } + + while (list) { + array[i] = g_strdup(list->data); + list = g_list_next(list); + i++; + } + array[len] = NULL; + + return array; +} + +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; + + _D("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) + _E("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) + _E("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) + _E("Failed to add paths %d", r); + + _D("security_manager_private_sharing_apply ++"); + r = security_manager_private_sharing_apply(h->shared_info->handle); + _D("security_manager_private_sharing_apply --"); + if (r != SECURITY_MANAGER_SUCCESS) { + _E("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; +} + +int _temporary_permission_apply(int pid, uid_t uid, shared_info_h handle) +{ + int ret; + app_status_h app_status; + + if (handle == NULL) + return -1; + + app_status = _app_status_find(pid); + if (app_status == NULL) + return -1; + + ret = _app_status_add_shared_info(app_status, handle->shared_info); + if (ret != 0) + return ret; + + handle->shared_info = NULL; + + return 0; +} + +int _temporary_permission_destroy(shared_info_h handle) +{ + int r; + + if (handle == NULL) + return -1; + + if (handle->shared_info) { /* back out */ + _D("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) + _E("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; +} + +int _temporary_permission_drop(int pid, uid_t uid) +{ + int r; + shared_info_t *sit; + app_status_h app_status; + GList *list; + + app_status = _app_status_find(pid); + if (app_status == NULL) + return -1; + + list = _app_status_get_shared_info_list(app_status); + if (!list) { + _D("list was null"); + return -1; + } + + while (list) { + sit = (shared_info_t *)list->data; + _D("revoke permission %s : %d", sit->owner_appid, pid); + r = security_manager_private_sharing_drop(sit->handle); + if (r != SECURITY_MANAGER_SUCCESS) + _E("revoke error %d", r); + security_manager_private_sharing_req_free(sit->handle); + list = g_list_next(list); + } + + return _app_status_clear_shared_info_list(app_status); +} + diff --git a/src/amd_signal.c b/src/amd_signal.c new file mode 100644 index 0000000..6039dd2 --- /dev/null +++ b/src/amd_signal.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2016 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. + */ + +#include +#include +#include +#include + +#include +#include + +#include "app_signal.h" +#include "amd_util.h" +#include "amd_signal.h" +#include "amd_cooldown.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; +} + +int _signal_send_watchdog(int pid, int signal_num) +{ + GError *err = NULL; + GDBusConnection *conn; + + if (_cooldown_get_status() == COOLDOWN_LIMIT) { + _E("cooldown status:LimitAction"); + _E("watchdog signal already sent for pid %d", pid); + return -1; + } + + conn = __get_system_conn(); + if (conn == NULL) + return -1; + + if (g_dbus_connection_emit_signal(conn, + NULL, + RESOURCED_PROC_OBJECT, + RESOURCED_PROC_INTERFACE, + RESOURCED_PROC_WATCHDOG_SIGNAL, + g_variant_new("(ii)", pid, signal_num), + &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; + } + + _W("send a watchdog signal done: %d", pid); + + return 0; +} + +int _signal_send_proc_prelaunch(const char *appid, const char *pkgid, + int attribute, int category) +{ + GError *err = NULL; + GVariant *param; + GDBusConnection *conn; + + conn = __get_system_conn(); + if (conn == NULL) + return -1; + + param = g_variant_new("(ssii)", appid, pkgid, attribute, category); + if (g_dbus_connection_emit_signal(conn, + NULL, + RESOURCED_PROC_OBJECT, + RESOURCED_PROC_INTERFACE, + RESOURCED_PROC_PRELAUNCH_SIGNAL, + param, + &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; + } + + _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("g_dbus_connection_send_message_with_reply_sync failed: %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(SYSTEM_BUS_NAME, + SYSTEM_OBJECT_PATH, + SYSTEM_INTERFACE_NAME, + SYSTEM_METHOD_NAME); + 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, 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)) { + ret = -1; + _E("Unable to send dbus message for acquring lock as %s", + err->message); + } + + _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, 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_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/amd_socket.c b/src/amd_socket.c new file mode 100644 index 0000000..60ce075 --- /dev/null +++ b/src/amd_socket.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2000 - 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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; + 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); + + error = 0; + 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/amd_splash_screen.c b/src/amd_splash_screen.c new file mode 100644 index 0000000..eef8c4e --- /dev/null +++ b/src/amd_splash_screen.c @@ -0,0 +1,786 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amd_appinfo.h" +#include "amd_util.h" +#include "amd_splash_screen.h" +#include "amd_wayland.h" +#include "amd_app_status.h" + +#define K_FAKE_EFFECT "__FAKE_EFFECT__" +#define APP_CONTROL_OPERATION_MAIN "http://tizen.org/appcontrol/operation/main" +#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; +}; + +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 int __init_splash_screen(void); +static int __init_rotation(void); + +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; +} + +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; + app_status_h app_status; + + if (si == NULL) + return FALSE; + + app_status = _app_status_find(si->pid); + if (app_status) { + if (_app_status_is_starting(app_status) == false) { + _W("% is not starting", si->pid); + return TRUE; + } + } + + si->timer = 0; + _splash_screen_destroy_image(si); + + return FALSE; +} + +static int __app_can_launch_splash_image(const struct appinfo *ai, + bundle *kb) +{ + const char *comp_type; + const char *fake_effect; + int display; + + comp_type = _appinfo_get_value(ai, AIT_COMPTYPE); + if (comp_type == NULL || strcmp(comp_type, APP_TYPE_UI) != 0) { + _D("component_type: %s", comp_type); + return -1; + } + + fake_effect = bundle_get_val(kb, K_FAKE_EFFECT); + if (fake_effect && strncmp(fake_effect, "OFF", strlen("OFF")) == 0) + return -1; + + _appinfo_get_int_value(ai, AIT_SPLASH_SCREEN_DISPLAY, &display); + if (!(display & APP_ENABLEMENT_MASK_ACTIVE)) + return -1; + + return 0; +} + +static struct appinfo_splash_image *__get_splash_image_info( + const struct appinfo *ai, bundle *kb, int cmd) +{ + struct appinfo_splash_image *ai_si; + const struct appinfo_splash_screen *ai_ss; + const char *operation; + GHashTable *tbl; + const struct appinfo *caller_ai; + const char *uid_str; + const char *caller_appid; + const char *comp_type; + uid_t uid = 0; + + ai_ss = _appinfo_get_ptr_value(ai, AIT_SPLASH_SCREEN); + if (ai_ss == NULL) + return NULL; + + if ((rotation.angle == 90 || rotation.angle == 270) + && rotation.auto_rotate == true) + tbl = ai_ss->landscape; + else + tbl = ai_ss->portrait; + + if (tbl == NULL) + return NULL; + + 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 g_hash_table_lookup(tbl, "launch-effect"); + + if (operation) { + ai_si = g_hash_table_lookup(tbl, operation); + if (ai_si) + return ai_si; + } + + 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; + + uid = atol(uid_str); + caller_ai = _appinfo_find(uid, caller_appid); + if (caller_ai == NULL) + return NULL; + + comp_type = _appinfo_get_value(caller_ai, AIT_COMPTYPE); + if (comp_type == NULL) + return NULL; + + if (!strcmp(comp_type, APP_TYPE_WATCH) || + !strcmp(comp_type, APP_TYPE_WIDGET)) + return g_hash_table_lookup(tbl, "launch-effect"); + + 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; +} + +splash_image_h _splash_screen_create_image(const struct appinfo *ai, + bundle *kb, int cmd, bool is_subapp) +{ + struct splash_image_s *si; + struct appinfo_splash_image *ai_si; + struct image_info_s *info; + const char *appid; + const char *src = NULL; + 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) + _W("Failed to initialize rotation"); + } + _D("angle: %d", rotation.angle); + + ai_si = __get_splash_image_info(ai, kb, cmd); + if (ai_si) { + src = ai_si->src; + if (access(src, F_OK) != 0) + return NULL; + if (strcasecmp(ai_si->type, "edj") == 0) + file_type = 1; + if (strcmp(ai_si->indicatordisplay, "false") == 0) + indicator = 0; + if (strcmp(ai_si->color_depth, "32") == 0) + color_depth = 32; + } 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) { + _E("out of memory"); + return NULL; + } + + si->image = tizen_launch_effect_create_splash_img( + tz_launch_effect); + if (si->image == NULL) { + _E("Failed to get launch image"); + free(si); + return NULL; + } + wl_display_flush(display); + + si->src = strdup(src); + if (si->src == NULL) { + _E("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) { + _E("Out of memory"); + _splash_screen_destroy_image(si); + return NULL; + } + + si->theme_type = strdup("default"); + if (si->theme_type == NULL) { + _E("Out of memory"); + _splash_screen_destroy_image(si); + return NULL; + } + + appid = _appinfo_get_value(ai, AIT_NAME); + si->appid = strdup(appid); + if (si->appid == NULL) { + _E("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; +} + +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) { + _E("out of memory"); + return; + } + + bundle_add(b, AUL_K_APPID, si->appid); + ret = bundle_encode(b, &raw_data, &len); + if (ret != BUNDLE_ERROR_NONE) { + _E("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); + + _D("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); +} + +void _splash_screen_send_pid(splash_image_h si, int pid) +{ + if (si == NULL) + return; + + si->pid = pid; + tizen_launch_splash_owner(si->image, pid); + wl_display_flush(display); +} + +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) { + _E("out of memory"); + return; + } + + bundle_add(b, AUL_K_APPID, appid); + ret = bundle_encode(b, &raw_data, &len); + if (ret != BUNDLE_ERROR_NONE) { + _E("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); + + _D("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 void __wl_listener_cb(void *data, struct wl_registry *registry, + unsigned int id, const char *interface, unsigned int version) +{ + if (interface && strcmp(interface, "tizen_launch_effect") == 0) { + _D("interface: %s", interface); + if (!tz_launch_effect) { + tz_launch_effect = wl_registry_bind(registry, id, + &tizen_launch_effect_interface, 1); + } + } +} + +static void __wl_listener_remove_cb(void *data, struct wl_registry *registry, + unsigned int id) +{ + if (tz_launch_effect) { + tizen_launch_effect_destroy(tz_launch_effect); + tz_launch_effect = NULL; + } +} + +static struct wl_registry_listener registry_listener = { + __wl_listener_cb, + __wl_listener_remove_cb +}; + +static int __init_splash_screen(void) +{ + if (!display) { + display = _wayland_get_display(); + if (!display) { + _E("Failed to get display"); + return -1; + } + } + + if (!tz_launch_effect) { + _E("Failed to bind tizen launch screen"); + return -1; + } + + splash_screen_initialized = 1; + + return 0; +} + +#ifdef TIZEN_FEATURE_AUTO_ROTATION +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; + } + + _D("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) { + _D("auto_rotate: %d, angle: %d", + rotation.auto_rotate, rotation.angle); + } +} +#endif /* TIZEN_FEATURE_AUTO_ROTATION */ + +static int __init_rotation(void) +{ +#ifdef TIZEN_FEATURE_AUTO_ROTATION + int ret; + bool r; + sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR); + + rotation.angle = 0; + rotation.handle = sensord_connect(sensor); + if (rotation.handle < 0) { + _W("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) { + _W("Failed to register event"); + sensord_disconnect(rotation.handle); + return -1; + } + + r = sensord_start(rotation.handle, 0); + if (!r) { + _W("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) { + _W("Failed to register callback for %s", + VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL); + } +#endif /* TIZEN_FEATURE_AUTO_ROTATION */ + 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) { + _E("out of memory"); + return NULL; + } + + return info; +} + +static int __validate_image_info(struct image_info_s *info) +{ + if (info == NULL) + return -1; + + if (info->name == NULL || + info->file == NULL || + info->orientation == NULL) + return -1; + + if (info->type == NULL) { + if (strstr(info->file, "edj")) + info->type = strdup("edj"); + else + info->type = strdup("img"); + } + + if (info->indicator_display == NULL) + info->indicator_display = strdup("true"); + + if (info->color_depth == NULL) + info->color_depth = strdup("24"); + + return 0; +} + +static void __parse_file(const char *file) +{ + FILE *fp; + char buf[LINE_MAX]; + char tok1[LINE_MAX]; + char tok2[LINE_MAX]; + struct image_info_s *info = NULL; + + fp = fopen(file, "rt"); + if (fp == NULL) + return; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + tok1[0] = '\0'; + tok2[0] = '\0'; + sscanf(buf, "%s %s", tok1, tok2); + + if (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[0] == '\0' || tok2[0] == '\0' || info == NULL) + 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); + } + } + + fclose(fp); +} + +static int __load_splash_screen_info(const char *path) +{ + DIR *dp; + struct dirent entry; + struct dirent *result = NULL; + char *ext; + char buf[PATH_MAX]; + + dp = opendir(path); + if (dp == NULL) + return -1; + + while (readdir_r(dp, &entry, &result) == 0 && result != 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; +} + +int _splash_screen_init(void) +{ + _D("init splash screen"); + + __load_splash_screen_info(SPLASH_SCREEN_INFO_PATH); + _wayland_add_registry_listener(®istry_listener, NULL); + + if (__init_rotation() < 0) + _W("Failed to initialize rotation"); + + return 0; +} + diff --git a/src/amd_suspend.c b/src/amd_suspend.c new file mode 100644 index 0000000..c153c2d --- /dev/null +++ b/src/amd_suspend.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include + +#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 void __destroy_proc_info_value(gpointer data) +{ + proc_info_t *proc = (proc_info_t *)data; + + if (proc) + free(proc); +} + +static void __prepare_to_suspend(int pid, uid_t uid) +{ + int ret; + int dummy; + + _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, ai); + aul_update_freezer_status(pid, "include"); +} + +void _suspend_init(void) +{ + if (!proc_info_tbl) { + proc_info_tbl = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, + __destroy_proc_info_value); + } + + _D("_amd_proc_init done"); +} + +void _suspend_fini(void) +{ + 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) != 0 && + strcmp(comp_type, APP_TYPE_SERVICE) != 0) + 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) + return true; + + return false; +} + +void _suspend_add_timer(int pid, const struct appinfo *ai) +{ + bool bg_allowed; + proc_info_t *proc; + + bg_allowed = _suspend_is_allowed_background(ai); + if (bg_allowed) + return; + + 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/amd_util.c b/src/amd_util.c new file mode 100644 index 0000000..b3462dc --- /dev/null +++ b/src/amd_util.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_widget.h" +#include "amd_app_status.h" + +#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; + +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]; + char err_buf[1024]; + + if (log_fd < 0) { + _E("error in opening the file: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + 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: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + + 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 void __low_mem_key_changed_cb(keynode_t *node, void *data) +{ + int status; + + if (vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status) < 0) + return; + + _D("mem status changed %d(normal:%d)", + status, VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL); + if (status == VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) { + _widget_restart_faulted(); + _app_status_send_fault_dead_for_oom_apps(); + } +} + +bool _util_check_oom(void) +{ + int ret; + int status; + + ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status); + if (ret == 0 && status >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) { + _W("low memory"); + return true; + } + + return false; +} + +static int __init_log(void) +{ + int offset; + char err_buf[1024]; + + log_fd = open(AMD_LOG_FILE, O_CREAT | O_WRONLY, 0644); + if (log_fd < 0) { + _E("error in opening the file: %s", + strerror_r(errno, err_buf, sizeof(err_buf))); + 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; +} + +int _util_init(void) +{ + if (__init_log() < 0) + return -1; + + if (vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, + __low_mem_key_changed_cb, NULL) < 0) { + _E("vconf initialize failed."); + return -1; + } + + return 0; +} + +void _util_fini(void) +{ + if (log_fd > 0) + close(log_fd); + + vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, + (vconf_callback_fn) __low_mem_key_changed_cb); +} diff --git a/src/amd_wayland.c b/src/amd_wayland.c new file mode 100644 index 0000000..3b58df6 --- /dev/null +++ b/src/amd_wayland.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amd_util.h" +#include "amd_wayland.h" +#include "amd_inotify.h" + +#define PATH_RUN_WAYLAND "/run/wayland-0" +#define PATH_RUN_WMREADY "/run/.wm_ready" +#define PATH_RUN "/run" + +struct wl_listener { + struct wl_registry_listener *registry_listener; + void *data; +}; + +static bool wl_ready; +static bool wm_ready; +static bool wl_initialized; +static struct wl_display *display; +static struct wl_registry *registry; +static GList *wl_list; +static int __wd; + +static void __init_wl(void); + +int _wayland_add_registry_listener( + struct wl_registry_listener *registry_listener, + void *data) +{ + struct wl_listener *listener; + + if (registry_listener == NULL) + return -1; + + listener = (struct wl_listener *)calloc(1, sizeof(struct wl_listener)); + if (listener == NULL) { + _E("out of memory"); + return -1; + } + + listener->registry_listener = registry_listener; + listener->data = data; + + wl_list = g_list_append(wl_list, listener); + + return 0; +} + +struct wl_display *_wayland_get_display(void) +{ + if (!display && wl_initialized) + __init_wl(); + + return display; +} + +static void __wl_listener_cb(void *data, struct wl_registry *reg, + unsigned int id, const char *interface, unsigned int version) +{ + GList *iter; + struct wl_listener *listener; + + for (iter = g_list_first(wl_list); iter; iter = g_list_next(iter)) { + listener = (struct wl_listener *)iter->data; + if (listener && listener->registry_listener && + listener->registry_listener->global) { + listener->registry_listener->global(listener->data, + reg, id, interface, version); + } + } +} + +static void __wl_listener_remove_cb(void *data, struct wl_registry *reg, + unsigned int id) +{ + GList *iter; + struct wl_listener *listener; + + iter = g_list_first(wl_list); + while (iter) { + listener = (struct wl_listener *)iter->data; + if (listener && listener->registry_listener && + listener->registry_listener->global_remove) { + listener->registry_listener->global_remove( + listener->data, reg, id); + } + + iter = g_list_next(iter); + wl_list = g_list_remove(wl_list, listener); + free(listener); + } +} + + +static const struct wl_registry_listener registry_listener = { + __wl_listener_cb, + __wl_listener_remove_cb +}; + +static void __init_wl(void) +{ + display = wl_display_connect(NULL); + if (display == NULL) { + _E("Failed to connect wayland display"); + return; + } + + registry = wl_display_get_registry(display); + if (registry == NULL) { + _E("Failed to get wayland registry"); + wl_display_disconnect(display); + display = NULL; + return; + } + + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_flush(display); + wl_display_roundtrip(display); +} + +static bool __wayland_monitor_cb(const char *event_name, void *data) +{ + if (event_name == NULL) + return true; + + if (strcmp(event_name, "wayland-0") == 0) { + _D("%s is created", event_name); + wl_ready = true; + } else if (strcmp(event_name, ".wm_ready") == 0) { + _D("%s is created", event_name); + wm_ready = true; + } + + if (wm_ready && wl_ready) { + wl_initialized = true; + __init_wl(); + __wd = 0; + return false; + } + + return true; +} + +int _wayland_init(void) +{ + _D("wayland init"); + + if (access(PATH_RUN_WAYLAND, F_OK) == 0) { + _D("%s exists", PATH_RUN_WAYLAND); + wl_ready = true; + } + + if (access(PATH_RUN_WMREADY, F_OK) == 0) { + _D("%s exists", PATH_RUN_WMREADY); + wm_ready = true; + } + + if (wl_ready && wm_ready) { + wl_initialized = true; + __init_wl(); + return 0; + } + + __wd = _inotify_add_watch(PATH_RUN, IN_CREATE, + __wayland_monitor_cb, NULL); + if (__wd < 0) { + _E("Failed to add inotify watch"); + return -1; + } + + return 0; +} + +void _wayland_finish(void) +{ + _D("wayland finish"); + + if (__wd > 0) + _inotify_rm_watch(__wd); + + if (registry) { + wl_registry_destroy(registry); + registry = NULL; + } + + if (display) { + wl_display_disconnect(display); + display = NULL; + } +} diff --git a/src/amd_widget.c b/src/amd_widget.c new file mode 100644 index 0000000..c9cb5c3 --- /dev/null +++ b/src/amd_widget.c @@ -0,0 +1,980 @@ +/* + * Copyright (c) 2015 - 2016 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 +#include +#include +#include +#include +#include +#include + +#include "amd_app_com.h" +#include "amd_request.h" +#include "amd_util.h" +#include "amd_launch.h" +#include "amd_widget.h" +#include "amd_app_status.h" +#include "amd_screen_connector.h" +#include "amd_socket.h" + +#ifndef AUL_K_WIDGET_OPERATION +#define AUL_K_WIDGET_OPERATION "__WIDGET_OP__" +#endif + +#ifndef AUL_K_WIDGET_FORCE +#define AUL_K_WIDGET_FORCE "__WIDGET_FORCE__" +#endif + +typedef struct _widget_t { + char *pkg_id; + char *widget_id; + int pid; + uid_t uid; + GList *instances; +} widget_t; + +typedef struct _restart_widget_info{ + int pid; + int uid; + char *widget_id; + int caller_pid; + char *pkgid; + guint timer; +} restart_widget_info; + +struct widget_status_info { + const char *endpoint; + const char *widget_id; + const char *instance_id; + const char *pkg_id; + const char *is_fault; + int status; + int pid; + uid_t uid; +}; + +static GList *__widgets; +static GList *__update_widgets; +static GHashTable *__restart_widget_tbl; + +static int __send_status_info(struct widget_status_info *info) +{ + char buf[MAX_PID_STR_BUFSZ]; + bundle *kb; + int r; + + kb = bundle_create(); + if (kb == NULL) { + _E("Out of memory"); + return -1; + } + + snprintf(buf, sizeof(buf), "%d", info->pid); + bundle_add(kb, AUL_K_COM_SENDER_PID, buf); + bundle_add(kb, AUL_K_WIDGET_ID, info->widget_id); + bundle_add_byte(kb, AUL_K_WIDGET_STATUS, &info->status, sizeof(int)); + + if (info->instance_id) + bundle_add(kb, AUL_K_WIDGET_INSTANCE_ID, info->instance_id); + if (info->pkg_id) + bundle_add(kb, AUL_K_PKGID, info->pkg_id); + if (info->is_fault) + bundle_add(kb, AUL_K_IS_FAULT, info->is_fault); + + r = _app_com_send(info->endpoint, getpgid(info->pid), kb, info->uid); + bundle_free(kb); + + return r; +} + +static void __restart_faulted_widget(int pid, int uid, const char *appid, + const char *pkgid, int caller_pid) +{ + _W("restart widget pid %d uid %d appid %s caller_pid %d pkgid %s", + pid, uid, appid, caller_pid, pkgid); + _widget_send_status_to_viewer( + pid, + uid, + appid, + caller_pid, + AUL_WIDGET_INSTANCE_EVENT_APP_RESTART_REQUEST); + + _widget_send_dead_signal_for_faulted( + pid, + uid, + pkgid, + appid); +} + +void _widget_restart_faulted() +{ + GHashTableIter iter; + gpointer key, value; + restart_widget_info *info; + + g_hash_table_iter_init(&iter, __restart_widget_tbl); + while (g_hash_table_iter_next(&iter, &key, &value)) { + info = (restart_widget_info *)value; + __restart_faulted_widget(info->pid, info->uid, info->widget_id, + info->pkgid, info->caller_pid); + } + g_hash_table_remove_all(__restart_widget_tbl); +} + +static void __destroy_widget_info(gpointer data) +{ + restart_widget_info *info = + (restart_widget_info *)data; + + if (info == NULL) + return; + if (info->widget_id) + free(info->widget_id); + if (info->pkgid) + free(info->pkgid); + free(info); +} + +static widget_t *__find_widget_by_pid(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 widget; + + widget_list = widget_list->next; + } + + return NULL; +} + +static char *__get_id_by_pid(int pid, uid_t uid) +{ + widget_t *widget; + + widget = __find_widget_by_pid(pid, uid); + if (!widget) + return NULL; + + return widget->widget_id; +} + +void _widget_dead_handler(int pid, int uid, + const char *pkgid, int caller_pid, bool is_exit_notified, + bool can_restart) +{ + bool is_widget = false; + restart_widget_info *widget_info; + char *widget_id; + + is_widget = _widget_exist(pid, uid); + if (!is_widget) + return; + + widget_id = __get_id_by_pid(pid, uid); + _W("restart process start %s", widget_id); + if (!can_restart) { + if(!is_exit_notified) { + _widget_send_dead_signal_for_faulted( + pid, + uid, + pkgid, + widget_id); + } else { + _widget_send_dead_signal(pid, uid, pkgid); + } + return; + } + + /* Restart fault widget logic start */ + if (!is_exit_notified) { + /* + * Screen info should be removed before send dead signal + * If not, _app_status_cleanup will send + * AUL_SCREEN_CONNECTOR_EVENT_TYPE_REMOVE + * event to the viewer and recreated instance with same + * instance id info will be removed by + * AUL_SCREEN_CONNECTOR_EVENT_TYPE_REMOVE event. + */ + _screen_connector_remove_app_screen_v2(pid, uid); + if (_util_check_oom()) { + widget_info = + g_hash_table_lookup( + __restart_widget_tbl, + widget_id); + if (widget_info == NULL) { + widget_info = (restart_widget_info *) + calloc(1, sizeof(restart_widget_info)); + widget_info->widget_id = strdup(widget_id); + widget_info->pkgid = strdup(pkgid); + widget_info->pid = pid; + widget_info->uid = uid; + widget_info->caller_pid = caller_pid; + g_hash_table_insert( + __restart_widget_tbl, + widget_info->widget_id, + widget_info); + } + } else { + __restart_faulted_widget(pid, uid, widget_id, + pkgid, + caller_pid); + } + } else { + /* + * If widget package is in update process + * widget dead signal will be sent after + * update process is completed so that + * viewer can restart widget at that time. + */ + if (_appinfo_is_pkg_updating(pkgid)) { + _widget_send_status_to_viewer(pid, uid, widget_id, + caller_pid, + AUL_WIDGET_INSTANCE_EVENT_APP_RESTART_REQUEST); + _widget_add_update_info(pkgid, pid, uid); + } else { + /* Normal exit */ + _widget_send_dead_signal(pid, uid, pkgid); + } + } +} + +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; +} + +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; +} + +int _widget_send_status_to_viewer(int pid, uid_t uid, const char *widget_id, + int viewer_pid, aul_widget_instance_event_e status) +{ + app_status_h viewer_app_status; + struct widget_status_info info; + + viewer_app_status = _app_status_find(viewer_pid); + if (viewer_app_status == NULL) + return -1; + + info.endpoint = _app_status_get_appid(viewer_app_status); + info.widget_id = widget_id; + info.instance_id = NULL; + info.pkg_id = NULL; + info.is_fault = NULL; + info.status = status; + info.pid = pid; + info.uid = _app_status_get_uid(viewer_app_status); + + return __send_status_info(&info); +} + +int _widget_send_dead_signal(int pid, uid_t uid, const char *pkgid) +{ + widget_t *widget = NULL; + GList *widget_list = __widgets; + struct widget_status_info info; + + while (widget_list) { + widget = (widget_t *)widget_list->data; + if (widget->pid == pid && widget->uid == uid) + break; + widget_list = widget_list->next; + } + + if (!widget) { + _E("cannot find widget pid : %d, uid %d", pid, uid); + return -1; + } + + info.endpoint = "widget.status"; + info.widget_id = widget->widget_id; + info.instance_id = NULL; + info.pkg_id = pkgid; + info.is_fault = "false"; + info.status = AUL_WIDGET_LIFE_CYCLE_EVENT_APP_DEAD; + info.pid = pid; + info.uid = uid; + + return __send_status_info(&info); +} + +int _widget_send_dead_signal_for_faulted(int pid, uid_t uid, + const char *pkgid, const char *widget_id) +{ + struct widget_status_info info = { + .endpoint = "widget.status", + .widget_id = widget_id, + .instance_id = NULL, + .pkg_id = pkgid, + .is_fault = "true", + .status = AUL_WIDGET_LIFE_CYCLE_EVENT_APP_DEAD, + .pid = pid, + .uid = uid + }; + + return __send_status_info(&info); +} + +int _widget_send_dead_signal_for_update_widget(const char *pkgid) +{ + widget_t *widget = NULL; + GList *widget_list = __update_widgets; + struct widget_status_info info; + int r; + + while (widget_list) { + widget = (widget_t *)widget_list->data; + if (strcmp(pkgid, widget->pkg_id) == 0) + break; + widget_list = widget_list->next; + } + + if (!widget) { + _E("cannot find update widget pkgid : %s", pkgid); + return -1; + } + + __update_widgets = g_list_remove(__update_widgets, widget); + + info.endpoint = "widget.status"; + info.widget_id = widget->widget_id; + info.instance_id = NULL; + info.pkg_id = pkgid; + info.is_fault = "true"; + info.status = AUL_WIDGET_LIFE_CYCLE_EVENT_APP_DEAD; + info.pid = widget->pid; + info.uid = widget->uid; + + r = __send_status_info(&info); + + if (widget->widget_id) + free(widget->widget_id); + if (widget->pkg_id) + free(widget->pkg_id); + free(widget); + + return r; +} + +int _widget_add_update_info(const char *pkg_id, int pid, uid_t uid) +{ + widget_t *widget; + widget_t *target_widget = NULL; + GList *widget_list = __widgets; + + if (!pkg_id) + return -1; + + while (widget_list) { + target_widget = (widget_t *)widget_list->data; + if (target_widget->pid == pid && target_widget->uid == uid) + break; + widget_list = widget_list->next; + } + if (!target_widget) { + _E("cannot find target_widget pid : %d, uid %d", pid, uid); + return -1; + } + + widget = (widget_t *)calloc(1, sizeof(widget_t)); + if (!widget) { + _E("out of memory"); + return -1; + } + + widget->widget_id = strdup(target_widget->widget_id); + widget->uid = uid; + widget->pid = pid; + widget->pkg_id = strdup(pkg_id); + __update_widgets = g_list_append(__update_widgets, widget); + + _D("update widget instance added: %s - %s (%d:%d)", widget->widget_id, pkg_id, + uid, pid); + return 0; +} + + +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) { + _E("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) { + _E("out of memory"); + free(id); + return -1; + } + widget->widget_id = strdup(widget_id); + 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); + + _D("widget instance added: %s - %s (%d:%d)", widget_id, instance_id, + uid, pid); + return 0; +} + +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); + _D("widget instace deleted: %s - %s (%d:%d)", widget->widget_id, + instance_id, widget->uid, widget->pid); + return 0; + } + + return -1; +} + +int _widget_list(const char *widget_id, 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) { + _E("out of memory"); + return -1; + } + + _D("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) { + _D("%s - %s", widget_id, instance_list->data); + bundle_add_str(rvalue, instance_list->data, + pid_buf); + instance_list = instance_list->next; + } + } + widget_list = widget_list->next; + } + + _D("end instance list"); + + fd = _request_remove_fd(req); + aul_sock_send_bundle_with_fd(fd, 0, rvalue, AUL_SOCK_NOREPLY); + + bundle_free(rvalue); + + return 0; +} + +static int __can_update_widget(bundle *kb, int pid) +{ + app_status_h widget_app_status; + const char *force; + int viewer_pid; + int focused_pid; + + force = bundle_get_val(kb, AUL_K_WIDGET_FORCE); + if (force && strcmp(force, "true") == 0) + return 0; + + widget_app_status = _app_status_find(pid); + if (widget_app_status == NULL) + return -EINVAL; + + viewer_pid = _app_status_get_org_caller_pid(widget_app_status); + focused_pid = _launch_get_focused_pid(); + if (viewer_pid != focused_pid) { + _D("The viewer app(%d) doesn't have focus", viewer_pid); + return -ECANCELED; + } + + return 0; +} + +int _widget_update(const char *widget_id, request_h req) +{ + char *instance_id = NULL; + char *appid = NULL; + bundle *kb = _request_get_bundle(req); + int ret = -1; + widget_t *widget; + GList *widget_list = __widgets; + bool dummy; + bool dummy_mode; + const char *operation; + bool update; + uid_t target_uid = _request_get_target_uid(req); + + if (!kb || !widget_id) { + _request_send_result(req, -EINVAL); + return -1; + } + + bundle_get_str(kb, AUL_K_APPID, &appid); + if (!appid) { + _E("missing appid:%s", widget_id); + _request_send_result(req, -EINVAL); + return -1; + } + + operation = bundle_get_val(kb, AUL_K_WIDGET_OPERATION); + if (operation && strcmp(operation, "update") == 0) + update = true; + else + update = false; + + 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; + widget_list = widget_list->next; + if (strcmp(widget->widget_id, widget_id) == 0 && + widget->uid == target_uid) { + bundle_del(kb, AUL_K_TARGET_PID); + bundle_add_byte(kb, AUL_K_TARGET_PID, + (void *)&widget->pid, + sizeof(widget->pid)); + + if (update) { + ret = __can_update_widget(kb, + widget->pid); + if (ret != 0) { + _W("Cannot update widget(%d)", + widget->pid); + _request_send_result(req, ret); + continue; + } + } + + ret = _launch_start_app(appid, req, &dummy, + &dummy_mode, false); + _D("update widget: %s(%d)", widget->widget_id, + widget->pid); + } + } + } 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)); + + if (update) { + ret = __can_update_widget(kb, widget->pid); + if (ret != 0) { + _E("Cannot update widget"); + _request_send_result(req, ret); + return ret; + } + } + } + + ret = _launch_start_app(appid, req, &dummy, &dummy_mode, false); + _D("update widget: %s", widget_id); + } + + return ret; +} + +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); + } + } + + _D("cleanup widget %d:%d", pid, uid); + + return 0; +} + +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; +} + +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; + _D("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); + _D("widget count %d", count); + } + widget_list = widget_list->next; + } + + return count; +} + +int _widget_verify_cmd(request_h req) +{ + bundle *kb = _request_get_bundle(req); + const char *command; + const char *instance_id; + const char *widget_id; + widget_t *widget; + + if (!kb) { + _E("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) { + _E("invalid command: %s - target instance %s is not exist", + command, instance_id); + return -EREJECTED; + } + + return 0; +} + +int _widget_init(void) +{ + _D("widget init"); + __restart_widget_tbl = + g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, __destroy_widget_info); + + return 0; +} + +void _widget_fini(void) +{ + _D("widget fini"); + + + if (__restart_widget_tbl) { + g_hash_table_destroy(__restart_widget_tbl); + __restart_widget_tbl = NULL; + } + + if (__widgets) + g_list_free_full(__widgets, __free_widget); +} + +void _widget_verify_instance(bundle *kb, int pid, uid_t uid) +{ + const char *operation; + const char *instance_id; + const char *widget_id; + widget_t *widget; + struct widget_status_info info; + + if (kb == NULL) + return; + + operation = bundle_get_val(kb, AUL_K_WIDGET_OPERATION); + if (operation == NULL) + return; + + if (strcmp(operation, "create") != 0) + return; + + widget_id = bundle_get_val(kb, AUL_K_WIDGET_ID); + if (widget_id == NULL) + return; + + instance_id = bundle_get_val(kb, AUL_K_WIDGET_INSTANCE_ID); + if (instance_id == NULL) + return; + + widget = __find_instance(widget_id, instance_id); + if (widget) + return; + + info.endpoint = "widget.status"; + info.widget_id = widget_id; + info.instance_id = instance_id; + info.pkg_id = NULL; + info.is_fault = NULL; + info.status = AUL_WIDGET_INSTANCE_EVENT_CREATE_ABORTED; + info.pid = pid; + info.uid = uid; + + __send_status_info(&info); +} + +static bundle *__create_bundle(widget_t *widget) +{ + char buf[MAX_PID_STR_BUFSZ]; + app_status_h app_status; + bundle *b; + + app_status = _app_status_find(widget->pid); + if (app_status == NULL) + return NULL; + + b = bundle_create(); + if (b == NULL) { + _E("Out of memory"); + return NULL; + } + + snprintf(buf, sizeof(buf), "%d", widget->pid); + bundle_add_str(b, AUL_K_PID, buf); + bundle_add_str(b, AUL_K_APPID, _app_status_get_appid(app_status)); + bundle_add_str(b, AUL_K_PKGID, _app_status_get_pkgid(app_status)); + bundle_add_str(b, AUL_K_EXEC, _app_status_get_app_path(app_status)); + bundle_add_str(b, AUL_K_WIDGET_ID, widget->widget_id); + + return b; +} + +static int __send_running_info(widget_t *widget, int fd) +{ + char buf[MAX_PID_STR_BUFSZ]; + const char *instance_id; + unsigned int surf; + bundle_raw *b_raw = NULL; + int len = 0; + GList *iter; + bundle *b; + int r; + + b = __create_bundle(widget); + if (b == NULL) { + _E("Failed to create bundle"); + aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR, + NULL, 0, AUL_SOCK_NOREPLY); + return -1; + } + + iter = widget->instances; + while (iter) { + instance_id = (const char *)iter->data; + surf = _screen_connector_get_surface_id(instance_id, + widget->uid); + snprintf(buf, sizeof(buf), "%u", surf); + bundle_del(b, AUL_K_WID); + bundle_add_str(b, AUL_K_WID, buf); + bundle_del(b, AUL_K_WIDGET_INSTANCE_ID); + bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id); + + bundle_encode(b, &b_raw, &len); + if (b_raw == NULL) { + _E("Failed to encode bundle"); + aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR, + NULL, 0, AUL_SOCK_NOREPLY); + bundle_free(b); + return -1; + } + + r = aul_sock_send_raw_with_fd(fd, APP_GET_INFO_OK, + (unsigned char *)b_raw, len, + AUL_SOCK_ASYNC | AUL_SOCK_BUNDLE); + if (r < 0) { + _E("Failed to send raw data: %d", r); + free(b_raw); + bundle_free(b); + return -1; + } + free(b_raw); + b_raw = NULL; + + iter = g_list_next(iter); + } + free(b_raw); + bundle_free(b); + + return 0; +} + +int _widget_send_running_info(request_h req) +{ + uid_t target_uid = _request_get_target_uid(req); + int fd = _request_remove_fd(req); + widget_t *widget; + GList *iter; + int count = 0; + int r; + + iter = __widgets; + while (iter) { + widget = (widget_t *)iter->data; + if (widget && widget->uid == target_uid) + count += g_list_length(widget->instances); + + iter = g_list_next(iter); + } + + if (count == 0) { + _E("Widget doesn't exist"); + _send_result_to_client(fd, -1); + return -1; + } + _send_result_to_client_v2(fd, count); + + iter = __widgets; + while (iter) { + widget = (widget_t *)iter->data; + if (widget && widget->uid == target_uid) { + r = __send_running_info(widget, fd); + if (r < 0) + break; + } + iter = g_list_next(iter); + } + close(fd); + + return 0; +} -- 2.7.4